ai-trust 0.1.3 → 0.2.1

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 (54) hide show
  1. package/README.md +43 -5
  2. package/dist/api/client.d.ts +32 -0
  3. package/dist/api/client.d.ts.map +1 -1
  4. package/dist/api/client.js +20 -0
  5. package/dist/api/client.js.map +1 -1
  6. package/dist/commands/audit.d.ts +2 -1
  7. package/dist/commands/audit.d.ts.map +1 -1
  8. package/dist/commands/audit.js +128 -6
  9. package/dist/commands/audit.js.map +1 -1
  10. package/dist/commands/batch.d.ts.map +1 -1
  11. package/dist/commands/batch.js +14 -0
  12. package/dist/commands/batch.js.map +1 -1
  13. package/dist/commands/check.d.ts +4 -1
  14. package/dist/commands/check.d.ts.map +1 -1
  15. package/dist/commands/check.js +156 -10
  16. package/dist/commands/check.js.map +1 -1
  17. package/dist/output/formatter.d.ts +2 -0
  18. package/dist/output/formatter.d.ts.map +1 -1
  19. package/dist/output/formatter.js +44 -3
  20. package/dist/output/formatter.js.map +1 -1
  21. package/dist/scanner/downloader.d.ts +15 -0
  22. package/dist/scanner/downloader.d.ts.map +1 -0
  23. package/dist/scanner/downloader.js +63 -0
  24. package/dist/scanner/downloader.js.map +1 -0
  25. package/dist/scanner/hma.d.ts +39 -0
  26. package/dist/scanner/hma.d.ts.map +1 -0
  27. package/dist/scanner/hma.js +91 -0
  28. package/dist/scanner/hma.js.map +1 -0
  29. package/dist/scanner/index.d.ts +24 -0
  30. package/dist/scanner/index.d.ts.map +1 -0
  31. package/dist/scanner/index.js +55 -0
  32. package/dist/scanner/index.js.map +1 -0
  33. package/dist/telemetry/contribute.d.ts +54 -0
  34. package/dist/telemetry/contribute.d.ts.map +1 -0
  35. package/dist/telemetry/contribute.js +123 -0
  36. package/dist/telemetry/contribute.js.map +1 -0
  37. package/dist/telemetry/index.d.ts +6 -0
  38. package/dist/telemetry/index.d.ts.map +1 -0
  39. package/dist/telemetry/index.js +6 -0
  40. package/dist/telemetry/index.js.map +1 -0
  41. package/dist/telemetry/opt-in.d.ts +49 -0
  42. package/dist/telemetry/opt-in.d.ts.map +1 -0
  43. package/dist/telemetry/opt-in.js +184 -0
  44. package/dist/telemetry/opt-in.js.map +1 -0
  45. package/dist/utils/parser.d.ts.map +1 -1
  46. package/dist/utils/parser.js +11 -3
  47. package/dist/utils/parser.js.map +1 -1
  48. package/dist/utils/prompt.d.ts +9 -0
  49. package/dist/utils/prompt.d.ts.map +1 -0
  50. package/dist/utils/prompt.js +31 -0
  51. package/dist/utils/prompt.js.map +1 -0
  52. package/dist/utils/resolve.js +6 -6
  53. package/dist/utils/resolve.js.map +1 -1
  54. package/package.json +1 -1
package/README.md CHANGED
@@ -41,13 +41,44 @@ Specify the package type explicitly:
41
41
  ai-trust check my-agent --type a2a_agent
42
42
  ```
43
43
 
44
+ #### Scan on demand
45
+
46
+ When a package isn't in the registry, ai-trust can download and scan it locally using [HackMyAgent](https://github.com/opena2a-org/hackmyagent). In interactive mode, you'll be prompted. In CI, use flags:
47
+
48
+ ```bash
49
+ # Auto-scan unknown packages, contribute results to the community registry
50
+ ai-trust check mcp-server-xyz --scan-if-missing --contribute
51
+
52
+ # Force re-scan even if registry data exists
53
+ ai-trust check server-filesystem --rescan
54
+
55
+ # Disable scanning entirely (registry lookup only)
56
+ ai-trust check server-filesystem --no-scan
57
+ ```
58
+
59
+ #### Community contribution
60
+
61
+ Scan results can be shared with the OpenA2A Registry as anonymized telemetry (check pass/fail and severity only -- no file paths, source code, or descriptions).
62
+
63
+ On first scan, ai-trust asks whether you'd like to contribute. Your choice is saved in `~/.opena2a/config.json` and shared across all OpenA2A tools (opena2a-cli, hackmyagent).
64
+
65
+ ```bash
66
+ # Contribute for this scan (non-interactive / CI)
67
+ ai-trust check chalk --rescan --contribute
68
+
69
+ # Configure globally via opena2a-cli
70
+ opena2a config set contribute true # opt in
71
+ opena2a config set contribute false # opt out
72
+ ```
73
+
44
74
  ### audit
45
75
 
46
- Parse `package.json` or `requirements.txt` and batch-query all dependencies.
76
+ Parse dependency files and batch-query all dependencies. Supports any `.json` file (package.json format) or `.txt` file (requirements.txt format). Unknown extensions are auto-detected.
47
77
 
48
78
  ```bash
49
79
  ai-trust audit package.json
50
80
  ai-trust audit requirements.txt
81
+ ai-trust audit deps/prod-deps.json
51
82
  ```
52
83
 
53
84
  Set a minimum trust level threshold (default: 3):
@@ -56,6 +87,12 @@ Set a minimum trust level threshold (default: 3):
56
87
  ai-trust audit package.json --min-trust 2
57
88
  ```
58
89
 
90
+ Scan dependencies not found in the registry:
91
+
92
+ ```bash
93
+ ai-trust audit package.json --scan-missing --contribute
94
+ ```
95
+
59
96
  ### batch
60
97
 
61
98
  Look up trust verdicts for multiple packages at once.
@@ -64,7 +101,7 @@ Look up trust verdicts for multiple packages at once.
64
101
  ai-trust batch express lodash chalk commander
65
102
  ```
66
103
 
67
- Apply the same type to all packages:
104
+ Filter by package type (packages that don't match are excluded):
68
105
 
69
106
  ```bash
70
107
  ai-trust batch my-server-a my-server-b --type mcp_server
@@ -95,9 +132,9 @@ ai-trust check express --no-color
95
132
 
96
133
  | Code | Meaning |
97
134
  |------|---------|
98
- | 0 | All queried packages meet the minimum trust threshold |
99
- | 1 | Error (network failure, file not found, server error, package not found) |
100
- | 2 | One or more packages fall below the minimum trust threshold (`--min-trust`) |
135
+ | 0 | All queried packages are safe / meet the trust threshold |
136
+ | 1 | Operational error (network failure, file not found, server error) |
137
+ | 2 | Policy signal: one or more packages have warning/blocked verdict or fall below `--min-trust` |
101
138
 
102
139
  ## Trust Levels
103
140
 
@@ -112,6 +149,7 @@ ai-trust check express --no-color
112
149
  ## Requirements
113
150
 
114
151
  - Node.js 18 or later
152
+ - [HackMyAgent](https://github.com/opena2a-org/hackmyagent) (optional, required for local scanning)
115
153
 
116
154
  ## Development
117
155
 
@@ -43,6 +43,34 @@ export interface PackageQuery {
43
43
  name: string;
44
44
  type?: string;
45
45
  }
46
+ export interface ScanSubmission {
47
+ name: string;
48
+ type?: string;
49
+ score: number;
50
+ maxScore: number;
51
+ findings: ScanFinding[];
52
+ projectType?: string;
53
+ scanTimestamp: string;
54
+ /** Ed25519 signature (hex) if user has an opena2a identity */
55
+ signature?: string;
56
+ /** Public key (hex) of the signer */
57
+ publicKey?: string;
58
+ }
59
+ export interface ScanFinding {
60
+ checkId: string;
61
+ name: string;
62
+ severity: string;
63
+ passed: boolean;
64
+ message: string;
65
+ category?: string;
66
+ /** Attack taxonomy class this finding maps to (from HMA taxonomy) */
67
+ attackClass?: string;
68
+ }
69
+ export interface PublishResponse {
70
+ accepted: boolean;
71
+ packageId?: string;
72
+ message?: string;
73
+ }
46
74
  export declare class PackageNotFoundError extends Error {
47
75
  readonly packageName: string;
48
76
  constructor(name: string);
@@ -52,5 +80,9 @@ export declare class RegistryClient {
52
80
  constructor(registryUrl: string);
53
81
  checkTrust(name: string, type?: string): Promise<TrustAnswer>;
54
82
  batchQuery(packages: PackageQuery[]): Promise<BatchResponse>;
83
+ /**
84
+ * Publish scan results to the community registry.
85
+ */
86
+ publishScan(submission: ScanSubmission): Promise<PublishResponse>;
55
87
  }
56
88
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,cAAc,CAAC;IAE9B,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAQD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,SAAgB,WAAW,EAAE,MAAM,CAAC;gBAExB,IAAI,EAAE,MAAM;CAKzB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEZ,WAAW,EAAE,MAAM;IAIzB,UAAU,CACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,CAAC;IAmCjB,UAAU,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC;CAkCnE"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -76,5 +76,25 @@ export class RegistryClient {
76
76
  },
77
77
  };
78
78
  }
79
+ /**
80
+ * Publish scan results to the community registry.
81
+ */
82
+ async publishScan(submission) {
83
+ const url = `${this.baseUrl}/api/v1/trust/publish`;
84
+ const response = await fetch(url, {
85
+ method: "POST",
86
+ headers: {
87
+ "Content-Type": "application/json",
88
+ "Accept": "application/json",
89
+ "User-Agent": USER_AGENT,
90
+ },
91
+ body: JSON.stringify(submission),
92
+ });
93
+ if (!response.ok) {
94
+ const body = await response.text();
95
+ throw new Error(`Registry publish failed (${response.status}): ${body}`);
96
+ }
97
+ return (await response.json());
98
+ }
79
99
  }
80
100
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  /**
2
- * oa2a audit - Parse dependency files and batch query trust.
2
+ * ai-trust audit - Parse dependency files and batch query trust.
3
+ * Supports scanning missing packages locally with HMA.
3
4
  */
4
5
  import type { Command } from "commander";
5
6
  export declare function registerAuditCommand(program: Command): void;
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/commands/audit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuE3D"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/commands/audit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0BzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuH3D"}
@@ -1,14 +1,21 @@
1
1
  /**
2
- * oa2a audit - Parse dependency files and batch query trust.
2
+ * ai-trust audit - Parse dependency files and batch query trust.
3
+ * Supports scanning missing packages locally with HMA.
3
4
  */
5
+ import chalk from "chalk";
4
6
  import { RegistryClient } from "../api/client.js";
5
7
  import { parseDependencyFile } from "../utils/parser.js";
6
- import { formatBatchResults, formatJson } from "../output/formatter.js";
8
+ import { formatBatchResults, formatJson, } from "../output/formatter.js";
9
+ import { isHmaAvailable, scanPackage } from "../scanner/index.js";
10
+ import { confirm } from "../utils/prompt.js";
11
+ import { isContributeEnabled, shouldPromptContribute, showContributePrompt, incrementScanCount, buildContributionPayload, submitContribution, } from "../telemetry/index.js";
7
12
  export function registerAuditCommand(program) {
8
13
  program
9
14
  .command("audit <file>")
10
15
  .description("Audit dependencies from package.json or requirements.txt")
11
16
  .option("--min-trust <level>", "minimum trust level threshold", "3")
17
+ .option("--scan-missing", "scan packages not found in registry using HMA")
18
+ .option("--contribute", "contribute scan results to community registry")
12
19
  .action(async (file, opts) => {
13
20
  const globalOpts = program.opts();
14
21
  const minTrust = parseInt(opts.minTrust, 10);
@@ -30,31 +37,146 @@ export function registerAuditCommand(program) {
30
37
  }
31
38
  const client = new RegistryClient(globalOpts.registryUrl);
32
39
  const response = await client.batchQuery(packages);
40
+ // Scan missing packages if requested
41
+ const notFound = response.results.filter((r) => !r.found);
42
+ if (notFound.length > 0 && opts.scanMissing) {
43
+ await scanMissingPackages(notFound, response.results, opts, globalOpts.registryUrl);
44
+ }
45
+ else if (notFound.length > 0 &&
46
+ !opts.scanMissing &&
47
+ process.stdin.isTTY) {
48
+ // Interactive: offer to scan
49
+ const shouldScan = await confirm(`${notFound.length} package(s) not in registry. Scan locally?`, false);
50
+ if (shouldScan) {
51
+ if (!(await isHmaAvailable())) {
52
+ console.error("HMA (HackMyAgent) is required for scanning. Install it with:");
53
+ console.error(" npm install -g hackmyagent");
54
+ }
55
+ else {
56
+ await scanMissingPackages(notFound, response.results, opts, globalOpts.registryUrl);
57
+ }
58
+ }
59
+ }
33
60
  if (globalOpts.json) {
34
61
  console.log(formatJson(response));
35
62
  }
36
63
  else {
37
64
  console.log(formatBatchResults(response, minTrust));
38
65
  }
39
- // Exit code 2 for policy violation (below threshold).
40
- // Exit code 1 is reserved for actual errors (network, server).
41
66
  const belowThreshold = response.results.some((r) => r.found && r.trustLevel < minTrust);
42
67
  if (belowThreshold) {
43
68
  process.exitCode = 2;
44
69
  }
45
70
  }
46
71
  catch (err) {
72
+ let message;
47
73
  if (err instanceof Error &&
48
74
  "code" in err &&
49
75
  err.code === "ENOENT") {
50
- console.error(`Error: File not found: ${file}`);
76
+ message = `File not found: ${file}`;
77
+ }
78
+ else {
79
+ message = err instanceof Error ? err.message : String(err);
80
+ }
81
+ if (globalOpts.json) {
82
+ console.log(formatJson({ file, error: message }));
51
83
  }
52
84
  else {
53
- const message = err instanceof Error ? err.message : String(err);
54
85
  console.error(`Error: ${message}`);
55
86
  }
56
87
  process.exitCode = 1;
57
88
  }
58
89
  });
59
90
  }
91
+ /**
92
+ * Scan packages not found in registry and update the results array in-place.
93
+ */
94
+ async function scanMissingPackages(notFound, allResults, opts, registryUrl) {
95
+ const available = await isHmaAvailable();
96
+ if (!available) {
97
+ console.error("HMA (HackMyAgent) is required for scanning. Install it with:");
98
+ console.error(" npm install -g hackmyagent");
99
+ return;
100
+ }
101
+ console.error(chalk.gray(`Scanning ${notFound.length} missing package(s)...`));
102
+ const scannedResults = [];
103
+ for (const pkg of notFound) {
104
+ try {
105
+ console.error(chalk.gray(` Scanning ${pkg.name}...`));
106
+ const scanResult = await scanPackage(pkg.name);
107
+ // Update the result in-place
108
+ const idx = allResults.findIndex((r) => r.name === pkg.name);
109
+ if (idx !== -1) {
110
+ allResults[idx] = {
111
+ ...allResults[idx],
112
+ found: true,
113
+ trustLevel: scanResult.trustLevel,
114
+ trustScore: scanResult.trustScore,
115
+ verdict: scanResult.verdict,
116
+ scanStatus: "local",
117
+ };
118
+ }
119
+ scannedResults.push({ name: pkg.name, scanResult });
120
+ }
121
+ catch (err) {
122
+ const message = err instanceof Error ? err.message : String(err);
123
+ console.error(chalk.yellow(` Could not scan ${pkg.name}: ${message}`));
124
+ }
125
+ }
126
+ // Handle community contribution for all scanned packages
127
+ if (scannedResults.length > 0) {
128
+ await handleAuditContribution(scannedResults, opts, registryUrl);
129
+ }
130
+ }
131
+ /**
132
+ * Handle community contribution after audit scanning.
133
+ * Follows the same opt-in flow as check: config -> prompt -> submit.
134
+ */
135
+ async function handleAuditContribution(scannedResults, opts, registryUrl) {
136
+ // Track scan count for each scanned package
137
+ for (let i = 0; i < scannedResults.length; i++) {
138
+ incrementScanCount();
139
+ }
140
+ if (opts.contribute) {
141
+ for (const { name, scanResult } of scannedResults) {
142
+ await submitAnonymizedTelemetry(name, scanResult, registryUrl);
143
+ }
144
+ return;
145
+ }
146
+ const configEnabled = isContributeEnabled();
147
+ if (configEnabled === true) {
148
+ // Already opted in: auto-contribute anonymized telemetry
149
+ for (const { name, scanResult } of scannedResults) {
150
+ await submitAnonymizedTelemetry(name, scanResult, registryUrl);
151
+ }
152
+ return;
153
+ }
154
+ if (configEnabled === false) {
155
+ return;
156
+ }
157
+ // Not yet configured: check if we should prompt
158
+ if (shouldPromptContribute()) {
159
+ const enabled = await showContributePrompt();
160
+ if (enabled) {
161
+ for (const { name, scanResult } of scannedResults) {
162
+ await submitAnonymizedTelemetry(name, scanResult, registryUrl);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ /**
168
+ * Submit anonymized telemetry to the registry (opt-in contribution).
169
+ */
170
+ async function submitAnonymizedTelemetry(name, scanResult, registryUrl) {
171
+ try {
172
+ const payload = buildContributionPayload(name, scanResult.scan.findings);
173
+ const result = await submitContribution(payload, registryUrl);
174
+ if (result.success) {
175
+ console.error(chalk.green(` Anonymized scan data shared: ${name}`));
176
+ }
177
+ }
178
+ catch {
179
+ // Non-fatal
180
+ }
181
+ }
60
182
  //# sourceMappingURL=audit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/commands/audit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAExE,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CACV,0DAA0D,CAC3D;SACA,MAAM,CACL,qBAAqB,EACrB,+BAA+B,EAC/B,GAAG,CACJ;SACA,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,IAA0B,EAAE,EAAE;QACzD,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAG9B,CAAC;QAEF,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACrE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAEjD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;gBAC5D,OAAO;YACT,CAAC;YAED,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;gBAC1B,OAAO,CAAC,KAAK,CACX,iCAAiC,QAAQ,CAAC,MAAM,kEAAkE,CACnH,CAAC;gBACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;YAC1D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAEnD,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtD,CAAC;YAED,sDAAsD;YACtD,+DAA+D;YAC/D,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,UAAU,GAAG,QAAQ,CAC1C,CAAC;YACF,IAAI,cAAc,EAAE,CAAC;gBACnB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,IACE,GAAG,YAAY,KAAK;gBACpB,MAAM,IAAI,GAAG;gBACZ,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAChD,CAAC;gBACD,OAAO,CAAC,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;YAClD,CAAC;iBAAM,CAAC;gBACN,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,OAAO,CAAC,KAAK,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;YACrC,CAAC;YACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/commands/audit.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../src/commands/batch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoE3D"}
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../src/commands/batch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqF3D"}
@@ -30,6 +30,20 @@ export function registerBatchCommand(program) {
30
30
  const client = new RegistryClient(globalOpts.registryUrl);
31
31
  try {
32
32
  const response = await client.batchQuery(packages);
33
+ // When --type is set, filter out packages that don't match
34
+ if (opts.type) {
35
+ for (const r of response.results) {
36
+ if (r.found &&
37
+ r.packageType &&
38
+ r.packageType !== opts.type) {
39
+ r.found = false;
40
+ r.verdict = "unknown";
41
+ r.trustLevel = 0;
42
+ response.meta.found--;
43
+ response.meta.notFound++;
44
+ }
45
+ }
46
+ }
33
47
  if (globalOpts.json) {
34
48
  console.log(formatJson(response));
35
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/commands/batch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,kBAAkB,CAAC;SAC3B,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,mBAAmB,EAAE,uCAAuC,CAAC;SACpE,MAAM,CACL,qBAAqB,EACrB,+BAA+B,EAC/B,GAAG,CACJ;SACA,MAAM,CACL,KAAK,EACH,KAAe,EACf,IAAyC,EACzC,EAAE;QACF,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAG9B,CAAC;QAEF,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,KAAK,CACX,qDAAqD,CACtD,CAAC;YACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CACX,6BAA6B,KAAK,CAAC,MAAM,kEAAkE,CAC5G,CAAC;YACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAmB,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACvD,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,CAAC,CAAC,CAAC;QAEJ,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QAE1D,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAEnD,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtD,CAAC;YAED,sDAAsD;YACtD,+DAA+D;YAC/D,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,UAAU,GAAG,QAAQ,CAC1C,CAAC;YACF,IAAI,cAAc,EAAE,CAAC;gBACnB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,CAAC,KAAK,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;YACnC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CACF,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/commands/batch.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  /**
2
- * oa2a check - Single package trust lookup.
2
+ * ai-trust check - Single package trust lookup with scan-on-demand.
3
+ *
4
+ * When a package isn't in the registry, offers to scan it locally with HMA
5
+ * and optionally contribute results to the community registry.
3
6
  */
4
7
  import type { Command } from "commander";
5
8
  export declare function registerCheckCommand(program: Command): void;
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiC3D"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6BzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2E3D"}
@@ -1,36 +1,182 @@
1
1
  /**
2
- * oa2a check - Single package trust lookup.
2
+ * ai-trust check - Single package trust lookup with scan-on-demand.
3
+ *
4
+ * When a package isn't in the registry, offers to scan it locally with HMA
5
+ * and optionally contribute results to the community registry.
3
6
  */
4
- import { RegistryClient } from "../api/client.js";
5
- import { formatCheckResult, formatJson } from "../output/formatter.js";
7
+ import chalk from "chalk";
8
+ import { RegistryClient, PackageNotFoundError } from "../api/client.js";
9
+ import { formatCheckResult, formatScanResult, formatJson, } from "../output/formatter.js";
6
10
  import { resolveAndLog } from "../utils/resolve.js";
11
+ import { isHmaAvailable, scanPackage } from "../scanner/index.js";
12
+ import { confirm } from "../utils/prompt.js";
13
+ import { isContributeEnabled, shouldPromptContribute, showContributePrompt, incrementScanCount, buildContributionPayload, submitContribution, } from "../telemetry/index.js";
7
14
  export function registerCheckCommand(program) {
8
15
  program
9
16
  .command("check <name>")
10
17
  .description("Look up trust information for a single package")
11
- .option("-t, --type <type>", "package type filter (mcp_server, a2a_agent, ai_tool, etc.). Note: the registry returns the canonical type; this flag filters but does not override the stored type.")
18
+ .option("-t, --type <type>", "package type filter (mcp_server, a2a_agent, ai_tool, etc.)")
19
+ .option("--scan-if-missing", "auto-scan packages not in registry (non-interactive)")
20
+ .option("--contribute", "auto-contribute scan results to community registry")
21
+ .option("--no-scan", "never scan, only query registry")
22
+ .option("--rescan", "force re-scan even if data exists")
23
+ .option("--stale-days <n>", "consider data stale after N days", "90")
12
24
  .action(async (rawName, opts) => {
13
25
  const globalOpts = program.opts();
14
26
  const name = resolveAndLog(rawName);
15
27
  const client = new RegistryClient(globalOpts.registryUrl);
16
28
  try {
17
29
  const result = await client.checkTrust(name, opts.type);
30
+ // Check for stale data
31
+ if (result.found && opts.rescan) {
32
+ await handleScanFlow(name, client, globalOpts, opts, "Re-scanning...");
33
+ return;
34
+ }
18
35
  if (globalOpts.json) {
19
36
  console.log(formatJson(result));
20
37
  }
21
38
  else {
22
39
  console.log(formatCheckResult(result));
23
40
  }
24
- // Exit code 1 if blocked or warning
25
- if (result.found && (result.verdict === "blocked" || result.verdict === "warning")) {
26
- process.exitCode = 1;
41
+ if (result.found &&
42
+ (result.verdict === "blocked" || result.verdict === "warning")) {
43
+ process.exitCode = 2;
27
44
  }
28
45
  }
29
46
  catch (err) {
30
- const message = err instanceof Error ? err.message : String(err);
31
- console.error(`Error: ${message}`);
32
- process.exitCode = 1;
47
+ if (err instanceof PackageNotFoundError && opts.scan !== false) {
48
+ await handleNotFound(name, client, globalOpts, opts);
49
+ }
50
+ else {
51
+ const message = err instanceof Error ? err.message : String(err);
52
+ if (globalOpts.json) {
53
+ console.log(formatJson({ name, found: false, error: message }));
54
+ }
55
+ else {
56
+ console.error(`Error: ${message}`);
57
+ }
58
+ process.exitCode = 1;
59
+ }
33
60
  }
34
61
  });
35
62
  }
63
+ async function handleNotFound(name, client, globalOpts, opts) {
64
+ // Non-interactive mode with --scan-if-missing
65
+ if (opts.scanIfMissing) {
66
+ await handleScanFlow(name, client, globalOpts, opts, `Package "${name}" not found in registry. Scanning...`);
67
+ return;
68
+ }
69
+ // Non-TTY: just report not found (scan must be opt-in via --scan-if-missing)
70
+ if (!process.stdin.isTTY) {
71
+ const msg = `Package "${name}" not found in the OpenA2A Registry. Use --scan-if-missing to scan locally.`;
72
+ if (globalOpts.json) {
73
+ console.log(formatJson({ name, found: false, error: msg }));
74
+ }
75
+ else {
76
+ console.error(msg);
77
+ }
78
+ process.exitCode = 1;
79
+ return;
80
+ }
81
+ // Interactive mode: ask the user
82
+ console.error(chalk.gray(`Package "${name}" not found in the OpenA2A Registry.`));
83
+ if (!(await checkHmaReady()))
84
+ return;
85
+ const shouldScan = await confirm("No trust data yet. Scan it now?", false);
86
+ if (!shouldScan) {
87
+ process.exitCode = 1;
88
+ return;
89
+ }
90
+ await handleScanFlow(name, client, globalOpts, opts, "Scanning...");
91
+ }
92
+ async function handleScanFlow(name, client, globalOpts, opts, statusMessage) {
93
+ if (!(await checkHmaReady()))
94
+ return;
95
+ console.error(chalk.gray(statusMessage));
96
+ let scanResult;
97
+ try {
98
+ scanResult = await scanPackage(name);
99
+ }
100
+ catch (err) {
101
+ const message = err instanceof Error ? err.message : String(err);
102
+ if (globalOpts.json) {
103
+ console.log(formatJson({ name, found: false, error: message }));
104
+ }
105
+ else {
106
+ console.error(`Error: ${message}`);
107
+ }
108
+ process.exitCode = 1;
109
+ return;
110
+ }
111
+ // Output scan results
112
+ if (globalOpts.json) {
113
+ console.log(formatJson(scanResult));
114
+ }
115
+ else {
116
+ console.log(formatScanResult(scanResult));
117
+ }
118
+ // Set exit code based on verdict (2 = policy signal, matching audit/batch)
119
+ if (scanResult.verdict === "blocked" || scanResult.verdict === "warning") {
120
+ process.exitCode = 2;
121
+ }
122
+ // Community contribution flow
123
+ await handleContribute(name, scanResult, globalOpts, opts);
124
+ }
125
+ async function handleContribute(name, scanResult, globalOpts, opts) {
126
+ // Track scan count regardless of contribution setting
127
+ incrementScanCount();
128
+ // Determine contribution mode:
129
+ // 1. --contribute flag: always contribute anonymized telemetry
130
+ // 2. Config enabled: auto-contribute anonymized telemetry
131
+ // 3. Not configured: maybe prompt
132
+ // 4. Config disabled: skip
133
+ if (opts.contribute) {
134
+ await submitAnonymizedTelemetry(name, scanResult, globalOpts.registryUrl);
135
+ return;
136
+ }
137
+ const configEnabled = isContributeEnabled();
138
+ if (configEnabled === true) {
139
+ // Already opted in: auto-contribute anonymized telemetry
140
+ await submitAnonymizedTelemetry(name, scanResult, globalOpts.registryUrl);
141
+ return;
142
+ }
143
+ if (configEnabled === false) {
144
+ // Explicitly opted out: skip
145
+ return;
146
+ }
147
+ // Not yet configured: check if we should prompt
148
+ if (shouldPromptContribute()) {
149
+ const enabled = await showContributePrompt();
150
+ if (enabled) {
151
+ await submitAnonymizedTelemetry(name, scanResult, globalOpts.registryUrl);
152
+ }
153
+ }
154
+ }
155
+ /**
156
+ * Submit anonymized telemetry to the registry (opt-in contribution).
157
+ * Only sends checkId, pass/fail, and severity. No file paths, descriptions, or code.
158
+ */
159
+ async function submitAnonymizedTelemetry(name, scanResult, registryUrl) {
160
+ try {
161
+ const payload = buildContributionPayload(name, scanResult.scan.findings);
162
+ const result = await submitContribution(payload, registryUrl);
163
+ if (result.success) {
164
+ console.error(chalk.green("Anonymized scan data shared with the community."));
165
+ }
166
+ // Silent on failure -- non-blocking
167
+ }
168
+ catch {
169
+ // Non-fatal: telemetry submission should never crash the scan
170
+ }
171
+ }
172
+ async function checkHmaReady() {
173
+ const available = await isHmaAvailable();
174
+ if (!available) {
175
+ console.error("HMA (HackMyAgent) is required for scanning. Install it with:");
176
+ console.error(" npm install -g hackmyagent");
177
+ process.exitCode = 1;
178
+ return false;
179
+ }
180
+ return true;
181
+ }
36
182
  //# sourceMappingURL=check.js.map