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.
- package/README.md +43 -5
- package/dist/api/client.d.ts +32 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +20 -0
- package/dist/api/client.js.map +1 -1
- package/dist/commands/audit.d.ts +2 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +128 -6
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/batch.d.ts.map +1 -1
- package/dist/commands/batch.js +14 -0
- package/dist/commands/batch.js.map +1 -1
- package/dist/commands/check.d.ts +4 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +156 -10
- package/dist/commands/check.js.map +1 -1
- package/dist/output/formatter.d.ts +2 -0
- package/dist/output/formatter.d.ts.map +1 -1
- package/dist/output/formatter.js +44 -3
- package/dist/output/formatter.js.map +1 -1
- package/dist/scanner/downloader.d.ts +15 -0
- package/dist/scanner/downloader.d.ts.map +1 -0
- package/dist/scanner/downloader.js +63 -0
- package/dist/scanner/downloader.js.map +1 -0
- package/dist/scanner/hma.d.ts +39 -0
- package/dist/scanner/hma.d.ts.map +1 -0
- package/dist/scanner/hma.js +91 -0
- package/dist/scanner/hma.js.map +1 -0
- package/dist/scanner/index.d.ts +24 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +55 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/telemetry/contribute.d.ts +54 -0
- package/dist/telemetry/contribute.d.ts.map +1 -0
- package/dist/telemetry/contribute.js +123 -0
- package/dist/telemetry/contribute.js.map +1 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +6 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/opt-in.d.ts +49 -0
- package/dist/telemetry/opt-in.d.ts.map +1 -0
- package/dist/telemetry/opt-in.js +184 -0
- package/dist/telemetry/opt-in.js.map +1 -0
- package/dist/utils/parser.d.ts.map +1 -1
- package/dist/utils/parser.js +11 -3
- package/dist/utils/parser.js.map +1 -1
- package/dist/utils/prompt.d.ts +9 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +31 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/resolve.js +6 -6
- package/dist/utils/resolve.js.map +1 -1
- 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
|
|
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
|
-
|
|
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
|
|
99
|
-
| 1 |
|
|
100
|
-
| 2 |
|
|
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
|
|
package/dist/api/client.d.ts
CHANGED
|
@@ -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
|
package/dist/api/client.d.ts.map
CHANGED
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
|
package/dist/api/client.js
CHANGED
|
@@ -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
|
package/dist/api/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAC1C,MAAM,UAAU,GAAG,YAAY,GAAG,CAAC,OAAO,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/audit.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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
|
|
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"}
|
package/dist/commands/audit.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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
|
-
|
|
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
|
|
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,
|
|
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"}
|
package/dist/commands/batch.js
CHANGED
|
@@ -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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"}
|
package/dist/commands/check.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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
|
|
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"}
|
package/dist/commands/check.js
CHANGED
|
@@ -1,36 +1,182 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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
|
|
5
|
-
import {
|
|
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.)
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
process.exitCode =
|
|
41
|
+
if (result.found &&
|
|
42
|
+
(result.verdict === "blocked" || result.verdict === "warning")) {
|
|
43
|
+
process.exitCode = 2;
|
|
27
44
|
}
|
|
28
45
|
}
|
|
29
46
|
catch (err) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|