agentverify 1.2.0 → 1.4.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.
package/dist/cli.mjs CHANGED
@@ -1,13 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  scan
4
- } from "./chunk-YOD7H7MC.mjs";
4
+ } from "./chunk-XVA2M2HS.mjs";
5
5
 
6
6
  // src/cli.ts
7
- import { readFileSync, readdirSync, statSync } from "fs";
7
+ import { readFileSync, readdirSync, statSync, appendFileSync, writeFileSync } from "fs";
8
8
  import { join, relative, extname } from "path";
9
- var VERSION = "1.2.0";
10
- var API_URL = "https://agentverify-api.agentverify.workers.dev/v1/scan";
9
+ var VERSION = "1.4.0";
10
+ var API_URL = process.env.AGENTVERIFY_API_URL ?? "https://agentverify-api.agentverify.workers.dev/v1/scan";
11
+ var A2SPA_DOCS_URL = "https://aimodularity.com/A2SPA/docs";
12
+ var EXIT_OK = 0;
13
+ var EXIT_NOT_VERIFIED = 1;
14
+ var EXIT_NOT_ASSESSED = 2;
15
+ var EXIT_EXECUTION_ERROR = 3;
11
16
  var c = {
12
17
  reset: "\x1B[0m",
13
18
  bold: "\x1B[1m",
@@ -22,6 +27,7 @@ var c = {
22
27
  var write = (value = "") => process.stdout.write(`${value}
23
28
  `);
24
29
  var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".ts", ".py", ".json", ".yaml", ".yml", ".md", ".mjs", ".cjs"]);
30
+ var MAX_SCAN_FILE_BYTES = 5 * 1024 * 1024;
25
31
  var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "vendor", "coverage", ".cache"]);
26
32
  function collectFiles(dir) {
27
33
  const files = [];
@@ -49,8 +55,13 @@ function parseArgs(argv) {
49
55
  key: "",
50
56
  file: "",
51
57
  json: false,
58
+ markdown: false,
59
+ ci: false,
60
+ allowNotAssessed: false,
52
61
  help: false,
53
- version: false
62
+ version: false,
63
+ policy: "",
64
+ summaryFile: ""
54
65
  };
55
66
  if (result.command === "--help" || result.command === "-h") {
56
67
  result.command = "";
@@ -65,6 +76,11 @@ function parseArgs(argv) {
65
76
  if (arg === "--key" || arg === "-k") result.key = args[++i] ?? "";
66
77
  else if (arg === "--file" || arg === "-f") result.file = args[++i] ?? "";
67
78
  else if (arg === "--json") result.json = true;
79
+ else if (arg === "--markdown") result.markdown = true;
80
+ else if (arg === "--ci") result.ci = true;
81
+ else if (arg === "--allow-not-assessed") result.allowNotAssessed = true;
82
+ else if (arg === "--policy") result.policy = args[++i] ?? "";
83
+ else if (arg === "--summary-file") result.summaryFile = args[++i] ?? "";
68
84
  else if (arg === "--help" || arg === "-h") result.help = true;
69
85
  else if (arg === "--version" || arg === "-v") result.version = true;
70
86
  else if (!arg.startsWith("-")) result.dir = arg;
@@ -88,6 +104,14 @@ ${c.bold}Options:${c.reset}
88
104
  --key, -k API key (or set AGENTVERIFY_API_KEY env var)
89
105
  --file, -f Scan a single file instead of a directory
90
106
  --json Output results as JSON
107
+ --markdown Output a Markdown summary
108
+ --ci CI mode: concise output and non-zero exit for NOT VERIFIED
109
+ --allow-not-assessed
110
+ In CI mode, do not fail only because content is NOT_ASSESSED
111
+ --policy <id> Evaluate a built-in policy profile against this scan's evidence
112
+ in addition to the scanner's own verdict (e.g. financial-agent)
113
+ --summary-file <path>
114
+ Write results as JSON to this path (in addition to any other output)
91
115
  --version, -v Print version
92
116
  --help, -h Show this help message
93
117
 
@@ -104,17 +128,123 @@ ${c.bold}Examples:${c.reset}
104
128
  ${c.gray}# Output as JSON (useful for CI/CD)${c.reset}
105
129
  agentverify scan . --key av_your_key --json
106
130
 
131
+ ${c.gray}# Markdown summary for pull requests${c.reset}
132
+ agentverify scan . --key av_your_key --markdown
133
+
134
+ ${c.bold}Exit codes (--ci):${c.reset}
135
+ 0 All scanned files verified
136
+ 1 NOT VERIFIED \u2014 a security/verification check failed
137
+ 2 NOT ASSESSED \u2014 insufficient evidence for a verdict (see --allow-not-assessed)
138
+ 3 Execution error \u2014 the scan itself could not run (bad key, network, missing file)
139
+
107
140
  ${c.bold}Get your API key:${c.reset}
108
141
  https://aimodularity.com/agentverify/dashboard
109
142
 
110
143
  ${c.bold}Docs:${c.reset}
111
144
  https://github.com/AI-Blockchain-Ventures/agentverify
145
+
146
+ ${c.bold}A2SPA docs:${c.reset}
147
+ ${A2SPA_DOCS_URL}
148
+ `);
149
+ }
150
+ function getTopBlocker(result) {
151
+ return result.reportInsights?.topBlocker ?? result.findings[0]?.title ?? "No blocking finding detected";
152
+ }
153
+ function getFixFirst(result) {
154
+ const fromInsights = result.reportInsights?.fixPriority?.filter((item) => item.priority === "fix_first").map((item) => item.title) ?? [];
155
+ const fallback = result.findings.slice(0, 3).map((item) => item.title);
156
+ return (fromInsights.length ? fromInsights : fallback).slice(0, 3);
157
+ }
158
+ function getRelevantThreatCategories(result) {
159
+ return (result.threatCategories ?? []).filter((item) => item.status !== "not_assessed").slice(0, 6).map((item) => `${item.label} (${item.status.replace("_", " ")})`);
160
+ }
161
+ function criticalCount(result) {
162
+ return result.findings.filter((f) => f.severity === "critical").length;
163
+ }
164
+ function highCount(result) {
165
+ return result.findings.filter((f) => f.severity === "high").length;
166
+ }
167
+ function fingerprintPreview(result) {
168
+ const hash = result.artifactFingerprint?.artifactHash;
169
+ return hash ? `${hash.slice(0, 12)}\u2026` : null;
170
+ }
171
+ function printDetailedSummary(result, fileName) {
172
+ const verified = result.verdict === "VERIFIED";
173
+ const verdictColor = verified ? c.green : result.verdict === "NOT_ASSESSED" ? c.yellow : c.red;
174
+ write(`
175
+ ${c.bold}${c.cyan}Agent Verify${c.reset}`);
176
+ write(`${c.gray}${fileName}${c.reset}`);
177
+ write(`${c.bold}Score:${c.reset} ${result.riskScore}/100`);
178
+ write(`${c.bold}Verdict:${c.reset} ${verdictColor}${result.verdict === "NOT_VERIFIED" ? "NOT VERIFIED" : result.verdict.replace("_", " ")}${c.reset}`);
179
+ write(`${c.bold}Risk level:${c.reset} ${result.riskLevel}`);
180
+ write(`${c.bold}Confidence:${c.reset} ${result.confidence}/100`);
181
+ write(`${c.bold}Critical / High findings:${c.reset} ${criticalCount(result)} / ${highCount(result)}`);
182
+ if (result.metadata?.scannerVersion) write(`${c.bold}Ruleset version:${c.reset} ${result.metadata.scannerVersion}`);
183
+ if (fingerprintPreview(result)) write(`${c.bold}Artifact fingerprint:${c.reset} ${fingerprintPreview(result)}`);
184
+ if (result.policyProfile) write(`${c.bold}Policy (${result.policyProfile}):${c.reset} ${result.policyResult === "PASS" ? `${c.green}PASS${c.reset}` : `${c.red}FAIL${c.reset}`}`);
185
+ write(`${c.bold}Top blocker:${c.reset} ${getTopBlocker(result)}`);
186
+ write(`
187
+ ${c.bold}Fix first:${c.reset}`);
188
+ const fixes = getFixFirst(result);
189
+ if (fixes.length) fixes.forEach((item, index) => write(` ${index + 1}. ${item}`));
190
+ else write(` No blocking fixes detected. Re-scan after any material change.`);
191
+ if (result.reportInsights?.nextAction) write(`
192
+ ${c.bold}Next action:${c.reset} ${result.reportInsights.nextAction}`);
193
+ const threats = getRelevantThreatCategories(result);
194
+ if (threats.length) {
195
+ write(`
196
+ ${c.bold}Threat categories:${c.reset}`);
197
+ threats.forEach((item) => write(` - ${item}`));
198
+ }
199
+ if (result.saved && result.reportId) write(`${c.bold}View report:${c.reset} https://aimodularity.com/agentverify/report/?id=${result.reportId}`);
200
+ write(`${c.bold}A2SPA docs:${c.reset} ${A2SPA_DOCS_URL}`);
201
+ write(`${c.gray}Re-scan:${c.reset} agentverify scan --file ${fileName} --key $AGENTVERIFY_API_KEY
202
+ `);
203
+ }
204
+ function markdownSummary(results, summary) {
205
+ const lines = ["# Agent Verify", "", `Files scanned: ${summary.total}`, `Verified: ${summary.verified}`, `Not verified: ${summary.notVerified}`, `Not assessed: ${summary.notAssessed}`, `Errors: ${summary.errors}`, ""];
206
+ for (const item of results) {
207
+ if (!item.result) {
208
+ lines.push(`## ${item.file}`, "", `Error: ${item.error ?? "Unknown error"}`, "");
209
+ continue;
210
+ }
211
+ lines.push(`## ${item.file}`, "", `Score: ${item.result.riskScore}/100`, `Verdict: ${item.result.verdict === "NOT_VERIFIED" ? "NOT VERIFIED" : item.result.verdict.replace("_", " ")}`, `Risk level: ${item.result.riskLevel}`, `Critical / High findings: ${criticalCount(item.result)} / ${highCount(item.result)}`);
212
+ if (item.result.metadata?.scannerVersion) lines.push(`Ruleset version: ${item.result.metadata.scannerVersion}`);
213
+ if (fingerprintPreview(item.result)) lines.push(`Artifact fingerprint: \`${fingerprintPreview(item.result)}\``);
214
+ if (item.result.policyProfile) lines.push(`Policy (${item.result.policyProfile}): ${item.result.policyResult}`);
215
+ lines.push(`Top blocker: ${getTopBlocker(item.result)}`, "");
216
+ const fixes = getFixFirst(item.result);
217
+ if (fixes.length) lines.push("Fix first:", ...fixes.map((fix, index) => `${index + 1}. ${fix}`), "");
218
+ const threats = getRelevantThreatCategories(item.result);
219
+ if (threats.length) lines.push("Threat categories:", ...threats.map((threat) => `- ${threat}`), "");
220
+ if (item.result.reportId) lines.push(`Report: https://aimodularity.com/agentverify/report/?id=${item.result.reportId}`, "");
221
+ }
222
+ lines.push(`A2SPA docs: ${A2SPA_DOCS_URL}`);
223
+ return lines.join("\n");
224
+ }
225
+ function writeGithubJobSummary(results, summary) {
226
+ const summaryPath = process.env.GITHUB_STEP_SUMMARY;
227
+ if (!summaryPath) return;
228
+ try {
229
+ appendFileSync(summaryPath, `${markdownSummary(results, summary)}
112
230
  `);
231
+ } catch (e) {
232
+ console.error(`Warning: could not write GitHub job summary: ${e instanceof Error ? e.message : e}`);
233
+ }
234
+ }
235
+ function writeSummaryFile(path, results, summary) {
236
+ if (!path) return;
237
+ try {
238
+ writeFileSync(path, JSON.stringify({ results, summary }, null, 2));
239
+ } catch (e) {
240
+ console.error(`Warning: could not write summary file: ${e instanceof Error ? e.message : e}`);
241
+ }
113
242
  }
114
243
  function printVerdict(result, fileName) {
115
244
  const verified = result.verdict === "VERIFIED";
116
- const icon = verified ? `${c.green}\u2713${c.reset}` : `${c.red}\u2717${c.reset}`;
117
- const verdict = verified ? `${c.green}VERIFIED${c.reset} ` : `${c.red}NOT VERIFIED${c.reset}`;
245
+ const notAssessed = result.verdict === "NOT_ASSESSED";
246
+ const icon = verified ? `${c.green}\u2713${c.reset}` : notAssessed ? `${c.yellow}\u26A0${c.reset}` : `${c.red}\u2717${c.reset}`;
247
+ const verdict = verified ? `${c.green}VERIFIED${c.reset} ` : notAssessed ? `${c.yellow}NOT ASSESSED${c.reset}` : `${c.red}NOT VERIFIED${c.reset}`;
118
248
  const score = verified ? `${c.green}${result.riskScore}/100${c.reset}` : result.riskScore >= 50 ? `${c.yellow}${result.riskScore}/100${c.reset}` : `${c.red}${result.riskScore}/100${c.reset}`;
119
249
  const findings = result.findings.length > 0 ? `${c.gray}\u2014 ${result.findings.length} finding${result.findings.length === 1 ? "" : "s"}${c.reset}` : "";
120
250
  const name = fileName.padEnd(30);
@@ -128,20 +258,23 @@ async function runScan(args) {
128
258
  console.error(`
129
259
  ${c.red}Error:${c.reset} API key required
130
260
  `);
131
- console.error(` Set with --key av_your_key or AGENTVERIFY_API_KEY env var`);
132
- console.error(` Get your key at https://aimodularity.com/agentverify/dashboard
261
+ console.error(` Set with --key av_your_key or AGENTVERIFY_API_KEY env var.`);
262
+ console.error(` Get your key at https://aimodularity.com/agentverify/dashboard/`);
263
+ console.error(` Example: AGENTVERIFY_API_KEY=av_your_key agentverify scan .
133
264
  `);
134
- process.exit(1);
265
+ process.exit(EXIT_EXECUTION_ERROR);
135
266
  }
136
267
  let files = [];
137
268
  if (args.file) {
138
269
  files = [args.file];
139
270
  } else {
140
271
  const dir = args.dir;
141
- write(`
272
+ if (!args.markdown && !args.json) {
273
+ write(`
142
274
  ${c.bold}Agent Verify${c.reset} ${c.gray}v${VERSION}${c.reset}`);
143
- write(`${c.gray}Scanning ${dir}...${c.reset}
275
+ write(`${c.gray}Scanning ${dir}...${c.reset}
144
276
  `);
277
+ }
145
278
  files = collectFiles(dir);
146
279
  if (files.length === 0) {
147
280
  write(`${c.yellow}No agent files found in ${dir}${c.reset}`);
@@ -153,16 +286,21 @@ ${c.bold}Agent Verify${c.reset} ${c.gray}v${VERSION}${c.reset}`);
153
286
  const jsonResults = [];
154
287
  let verified = 0;
155
288
  let notVerified = 0;
289
+ let notAssessed = 0;
156
290
  let errors = 0;
157
291
  const CONCURRENCY = 3;
158
292
  for (let i = 0; i < files.length; i += CONCURRENCY) {
159
293
  const batch = files.slice(i, i + CONCURRENCY);
160
294
  const batchResults = await Promise.allSettled(
161
295
  batch.map(async (filePath) => {
296
+ const fileStat = statSync(filePath);
297
+ if (fileStat.size > MAX_SCAN_FILE_BYTES) {
298
+ throw new Error(`File is ${(fileStat.size / 1024 / 1024).toFixed(1)}MB, over the ${MAX_SCAN_FILE_BYTES / 1024 / 1024}MB scan limit \u2014 skipped`);
299
+ }
162
300
  const content = readFileSync(filePath, "utf-8");
163
301
  const relPath = relative(args.dir === "." ? process.cwd() : args.dir, filePath);
164
302
  const result = await scan(
165
- { content, fileName: relPath },
303
+ { content, fileName: relPath, policyId: args.policy || void 0 },
166
304
  { apiKey: args.key, apiUrl: API_URL }
167
305
  );
168
306
  return { filePath, relPath, result };
@@ -172,9 +310,13 @@ ${c.bold}Agent Verify${c.reset} ${c.gray}v${VERSION}${c.reset}`);
172
310
  const outcome = batchResults[j];
173
311
  if (outcome.status === "fulfilled") {
174
312
  const { relPath, result } = outcome.value;
175
- if (!args.json) printVerdict(result, relPath);
313
+ if (!args.json && !args.markdown) {
314
+ if (args.file && !args.ci) printDetailedSummary(result, relPath);
315
+ else printVerdict(result, relPath);
316
+ }
176
317
  jsonResults.push({ file: relPath, result, error: null });
177
318
  if (result.verdict === "VERIFIED") verified++;
319
+ else if (result.verdict === "NOT_ASSESSED") notAssessed++;
178
320
  else notVerified++;
179
321
  } else {
180
322
  const filePath = batch[j];
@@ -188,32 +330,58 @@ ${c.bold}Agent Verify${c.reset} ${c.gray}v${VERSION}${c.reset}`);
188
330
  }
189
331
  }
190
332
  }
333
+ const summary = { total: files.length, verified, notVerified, notAssessed, errors };
334
+ writeGithubJobSummary(jsonResults, summary);
335
+ writeSummaryFile(args.summaryFile, jsonResults, summary);
191
336
  if (args.json) {
192
- write(JSON.stringify({ results: jsonResults, summary: { total: files.length, verified, notVerified, errors } }, null, 2));
337
+ write(JSON.stringify({ results: jsonResults, summary }, null, 2));
338
+ if (errors > 0) process.exit(EXIT_EXECUTION_ERROR);
339
+ if (args.ci) {
340
+ if (notVerified > 0) process.exit(EXIT_NOT_VERIFIED);
341
+ if (notAssessed > 0 && !args.allowNotAssessed) process.exit(EXIT_NOT_ASSESSED);
342
+ }
193
343
  return;
194
344
  }
345
+ if (args.markdown) {
346
+ write(markdownSummary(jsonResults, summary));
347
+ if (errors > 0) process.exit(EXIT_EXECUTION_ERROR);
348
+ if (args.ci) {
349
+ if (notVerified > 0) process.exit(EXIT_NOT_VERIFIED);
350
+ if (notAssessed > 0 && !args.allowNotAssessed) process.exit(EXIT_NOT_ASSESSED);
351
+ }
352
+ return;
353
+ }
354
+ const savedReports = jsonResults.filter((item) => item.result?.saved && item.result.reportId).length;
195
355
  write(`
196
356
  ${c.gray}${"\u2500".repeat(60)}${c.reset}`);
197
357
  write(`${c.bold}Agent Verify Scan Complete${c.reset}`);
198
358
  write(`${c.gray}Files scanned:${c.reset} ${files.length}`);
199
359
  write(`${c.green}Verified:${c.reset} ${verified}`);
200
360
  if (notVerified > 0) write(`${c.red}Not Verified:${c.reset} ${notVerified}`);
361
+ if (notAssessed > 0) write(`${c.yellow}Not Assessed:${c.reset} ${notAssessed}`);
201
362
  if (errors > 0) write(`${c.yellow}Errors:${c.reset} ${errors}`);
202
363
  write(`${c.gray}${"\u2500".repeat(60)}${c.reset}`);
203
- write(`
204
- ${c.gray}View reports: https://aimodularity.com/agentverify/dashboard${c.reset}
364
+ if (savedReports > 0) write(`
365
+ ${c.gray}Saved CLI reports appear in your dashboard: https://aimodularity.com/agentverify/dashboard/${c.reset}`);
366
+ else write(`
367
+ ${c.gray}No dashboard report was saved. Check API key access and retry if you need dashboard sync.${c.reset}`);
368
+ write(`${c.gray}A2SPA docs: ${A2SPA_DOCS_URL}${c.reset}
205
369
  `);
206
- if (notVerified > 0) process.exit(1);
370
+ if (errors > 0) process.exit(EXIT_EXECUTION_ERROR);
371
+ if (args.ci) {
372
+ if (notVerified > 0) process.exit(EXIT_NOT_VERIFIED);
373
+ if (notAssessed > 0 && !args.allowNotAssessed) process.exit(EXIT_NOT_ASSESSED);
374
+ }
207
375
  }
208
376
  async function main() {
209
377
  const args = parseArgs(process.argv);
210
378
  if (args.version) {
211
379
  write(`agentverify v${VERSION}`);
212
- process.exit(0);
380
+ process.exit(EXIT_OK);
213
381
  }
214
382
  if (args.help || !args.command) {
215
383
  printHelp();
216
- process.exit(0);
384
+ process.exit(EXIT_OK);
217
385
  }
218
386
  if (args.command === "scan") {
219
387
  await runScan(args);
@@ -222,11 +390,11 @@ async function main() {
222
390
  ${c.red}Unknown command: ${args.command}${c.reset}`);
223
391
  console.error(`Run ${c.cyan}agentverify --help${c.reset} for usage
224
392
  `);
225
- process.exit(1);
393
+ process.exit(EXIT_EXECUTION_ERROR);
226
394
  }
227
395
  }
228
396
  main().catch((err) => {
229
397
  console.error(`
230
398
  ${c.red}Fatal error:${c.reset}`, err instanceof Error ? err.message : err);
231
- process.exit(1);
399
+ process.exit(EXIT_EXECUTION_ERROR);
232
400
  });
package/dist/sdk.d.mts CHANGED
@@ -2,25 +2,133 @@ interface ScanInput {
2
2
  content: string;
3
3
  fileName?: string;
4
4
  platform?: string;
5
+ /** One of the built-in policy profile ids (e.g. "financial-agent") — evaluated server-side against this scan's evidence, in addition to (never instead of) the scanner's own verdict. */
6
+ policyId?: string;
7
+ }
8
+ interface ArtifactFingerprint {
9
+ artifactHash: string;
10
+ artifactHashAlgorithm: string;
11
+ artifactFingerprintVersion: string;
12
+ }
13
+ interface ReportIntegrity {
14
+ reportHash: string;
15
+ algorithm: string;
16
+ schemaVersion: string;
17
+ scannerVersion: string;
18
+ scanId: string;
19
+ timestamp: string;
20
+ }
21
+ interface SignedAttestation {
22
+ payload: Record<string, unknown>;
23
+ signature: string;
24
+ algorithm: string;
25
+ publicKey: Record<string, unknown>;
26
+ }
27
+ type Verdict = 'VERIFIED' | 'NOT_VERIFIED' | 'NOT_ASSESSED';
28
+ type RiskLevel = 'Low Risk' | 'Moderate Risk' | 'High Risk';
29
+ type Category = 'A' | 'B';
30
+ type Severity = 'critical' | 'high' | 'medium' | 'low';
31
+ type ThreatCategoryStatus = 'detected' | 'possible' | 'missing_evidence' | 'not_assessed';
32
+ interface ThreatCategoryAssessment {
33
+ id: string;
34
+ label: string;
35
+ status: ThreatCategoryStatus;
36
+ severity: Severity;
37
+ whatItMeans: string;
38
+ evidencePattern: string;
39
+ whyItMatters: string;
40
+ recommendedFix: string;
41
+ a2spaImpact: string;
5
42
  }
6
43
  interface Finding {
44
+ id: string;
45
+ code: string;
7
46
  title: string;
8
- category: 'A' | 'B';
9
- severity: 'critical' | 'high' | 'medium' | 'low';
47
+ category: Category;
48
+ severity: Severity;
10
49
  whatIsWrong: string;
11
50
  whyItMatters: string;
12
- recommendedFix: string;
13
51
  evidence?: string;
52
+ recommendedFix: string;
53
+ fixCode?: string;
54
+ quickFix?: string;
55
+ compliance?: {
56
+ owasp?: string[];
57
+ nist?: string[];
58
+ soc2?: string[];
59
+ };
60
+ }
61
+ interface RuntimeBOM {
62
+ detectedLanguage: string;
63
+ detectedFramework: string | null;
64
+ detectedPlatform: string | null;
65
+ agentName: string | null;
66
+ toolAccessLevel: 'Restricted' | 'Unrestricted' | 'Unknown';
67
+ credentialExposure: 'Detected' | 'Not Detected';
68
+ memoryPersistence: 'Bounded' | 'Unbounded' | 'Unknown';
69
+ auditLogging: 'Present' | 'Absent' | 'Unknown';
70
+ humanGates: 'Present' | 'Absent' | 'Unknown';
71
+ rateLimiting: 'Present' | 'Absent' | 'Unknown';
72
+ promptInjectionSurface: 'Detected' | 'Not Detected' | 'Unknown';
73
+ delegationScope: 'Scoped' | 'Unscoped' | 'Unknown';
74
+ }
75
+ interface CategoryScore {
76
+ category: Category;
77
+ label: string;
78
+ score: number;
79
+ maxScore: number;
80
+ findingCount: number;
81
+ }
82
+ interface FixPriorityItem {
83
+ code: string;
84
+ title: string;
85
+ severity: Severity;
86
+ priority: 'fix_first' | 'fix_next' | 'nice_to_have';
87
+ reason: string;
88
+ }
89
+ interface ReportInsights {
90
+ executionReadinessScore: number;
91
+ a2spaReadinessScore: number;
92
+ remediationProgressScore: number;
93
+ topBlocker: string | null;
94
+ nextAction: string;
95
+ scoreExplanation: string[];
96
+ improvesScore: string[];
97
+ verificationBlockers: string[];
98
+ fixPriority: FixPriorityItem[];
14
99
  }
15
100
  interface ScanResult {
16
- verdict: 'VERIFIED' | 'NOT VERIFIED';
101
+ schemaVersion: '1.3.0';
102
+ reportId: string;
103
+ verdict: Verdict;
17
104
  riskScore: number;
18
- riskLevel: 'Low Risk' | 'Moderate Risk' | 'High Risk';
105
+ riskLevel: RiskLevel;
106
+ confidence: number;
107
+ optimizationScore: number;
108
+ reportInsights?: ReportInsights;
109
+ threatCategories?: ThreatCategoryAssessment[];
19
110
  findings: Finding[];
20
- reportId: string;
21
- scannedAt: string;
111
+ categoryScores: CategoryScore[];
112
+ bom: RuntimeBOM;
113
+ metadata: {
114
+ schemaVersion: '1.3.0';
115
+ scannerVersion: string;
116
+ fileName: string;
117
+ fileSize: number;
118
+ scannedAt: string;
119
+ detectedLanguage: string;
120
+ detectedFramework: string | null;
121
+ selectedPlatform: string | null;
122
+ agentName: string | null;
123
+ scanDuration: number;
124
+ };
22
125
  saved: boolean;
23
- reportUrl?: string;
126
+ reportUrl?: string | null;
127
+ artifactFingerprint?: ArtifactFingerprint;
128
+ reportIntegrity?: ReportIntegrity;
129
+ policyProfile?: string | null;
130
+ policyResult?: string | null;
131
+ attestation?: SignedAttestation | null;
24
132
  }
25
133
  interface ScanOptions {
26
134
  apiKey: string;
@@ -39,7 +147,7 @@ interface ScanOptions {
39
147
  * { apiKey: process.env.AGENTVERIFY_API_KEY }
40
148
  * )
41
149
  *
42
- * result.verdict // 'VERIFIED' | 'NOT VERIFIED'
150
+ * result.verdict // 'VERIFIED' | 'NOT_VERIFIED' | 'NOT_ASSESSED'
43
151
  * result.riskScore // 0-100
44
152
  * result.findings // Array of findings
45
153
  */
package/dist/sdk.d.ts CHANGED
@@ -2,25 +2,133 @@ interface ScanInput {
2
2
  content: string;
3
3
  fileName?: string;
4
4
  platform?: string;
5
+ /** One of the built-in policy profile ids (e.g. "financial-agent") — evaluated server-side against this scan's evidence, in addition to (never instead of) the scanner's own verdict. */
6
+ policyId?: string;
7
+ }
8
+ interface ArtifactFingerprint {
9
+ artifactHash: string;
10
+ artifactHashAlgorithm: string;
11
+ artifactFingerprintVersion: string;
12
+ }
13
+ interface ReportIntegrity {
14
+ reportHash: string;
15
+ algorithm: string;
16
+ schemaVersion: string;
17
+ scannerVersion: string;
18
+ scanId: string;
19
+ timestamp: string;
20
+ }
21
+ interface SignedAttestation {
22
+ payload: Record<string, unknown>;
23
+ signature: string;
24
+ algorithm: string;
25
+ publicKey: Record<string, unknown>;
26
+ }
27
+ type Verdict = 'VERIFIED' | 'NOT_VERIFIED' | 'NOT_ASSESSED';
28
+ type RiskLevel = 'Low Risk' | 'Moderate Risk' | 'High Risk';
29
+ type Category = 'A' | 'B';
30
+ type Severity = 'critical' | 'high' | 'medium' | 'low';
31
+ type ThreatCategoryStatus = 'detected' | 'possible' | 'missing_evidence' | 'not_assessed';
32
+ interface ThreatCategoryAssessment {
33
+ id: string;
34
+ label: string;
35
+ status: ThreatCategoryStatus;
36
+ severity: Severity;
37
+ whatItMeans: string;
38
+ evidencePattern: string;
39
+ whyItMatters: string;
40
+ recommendedFix: string;
41
+ a2spaImpact: string;
5
42
  }
6
43
  interface Finding {
44
+ id: string;
45
+ code: string;
7
46
  title: string;
8
- category: 'A' | 'B';
9
- severity: 'critical' | 'high' | 'medium' | 'low';
47
+ category: Category;
48
+ severity: Severity;
10
49
  whatIsWrong: string;
11
50
  whyItMatters: string;
12
- recommendedFix: string;
13
51
  evidence?: string;
52
+ recommendedFix: string;
53
+ fixCode?: string;
54
+ quickFix?: string;
55
+ compliance?: {
56
+ owasp?: string[];
57
+ nist?: string[];
58
+ soc2?: string[];
59
+ };
60
+ }
61
+ interface RuntimeBOM {
62
+ detectedLanguage: string;
63
+ detectedFramework: string | null;
64
+ detectedPlatform: string | null;
65
+ agentName: string | null;
66
+ toolAccessLevel: 'Restricted' | 'Unrestricted' | 'Unknown';
67
+ credentialExposure: 'Detected' | 'Not Detected';
68
+ memoryPersistence: 'Bounded' | 'Unbounded' | 'Unknown';
69
+ auditLogging: 'Present' | 'Absent' | 'Unknown';
70
+ humanGates: 'Present' | 'Absent' | 'Unknown';
71
+ rateLimiting: 'Present' | 'Absent' | 'Unknown';
72
+ promptInjectionSurface: 'Detected' | 'Not Detected' | 'Unknown';
73
+ delegationScope: 'Scoped' | 'Unscoped' | 'Unknown';
74
+ }
75
+ interface CategoryScore {
76
+ category: Category;
77
+ label: string;
78
+ score: number;
79
+ maxScore: number;
80
+ findingCount: number;
81
+ }
82
+ interface FixPriorityItem {
83
+ code: string;
84
+ title: string;
85
+ severity: Severity;
86
+ priority: 'fix_first' | 'fix_next' | 'nice_to_have';
87
+ reason: string;
88
+ }
89
+ interface ReportInsights {
90
+ executionReadinessScore: number;
91
+ a2spaReadinessScore: number;
92
+ remediationProgressScore: number;
93
+ topBlocker: string | null;
94
+ nextAction: string;
95
+ scoreExplanation: string[];
96
+ improvesScore: string[];
97
+ verificationBlockers: string[];
98
+ fixPriority: FixPriorityItem[];
14
99
  }
15
100
  interface ScanResult {
16
- verdict: 'VERIFIED' | 'NOT VERIFIED';
101
+ schemaVersion: '1.3.0';
102
+ reportId: string;
103
+ verdict: Verdict;
17
104
  riskScore: number;
18
- riskLevel: 'Low Risk' | 'Moderate Risk' | 'High Risk';
105
+ riskLevel: RiskLevel;
106
+ confidence: number;
107
+ optimizationScore: number;
108
+ reportInsights?: ReportInsights;
109
+ threatCategories?: ThreatCategoryAssessment[];
19
110
  findings: Finding[];
20
- reportId: string;
21
- scannedAt: string;
111
+ categoryScores: CategoryScore[];
112
+ bom: RuntimeBOM;
113
+ metadata: {
114
+ schemaVersion: '1.3.0';
115
+ scannerVersion: string;
116
+ fileName: string;
117
+ fileSize: number;
118
+ scannedAt: string;
119
+ detectedLanguage: string;
120
+ detectedFramework: string | null;
121
+ selectedPlatform: string | null;
122
+ agentName: string | null;
123
+ scanDuration: number;
124
+ };
22
125
  saved: boolean;
23
- reportUrl?: string;
126
+ reportUrl?: string | null;
127
+ artifactFingerprint?: ArtifactFingerprint;
128
+ reportIntegrity?: ReportIntegrity;
129
+ policyProfile?: string | null;
130
+ policyResult?: string | null;
131
+ attestation?: SignedAttestation | null;
24
132
  }
25
133
  interface ScanOptions {
26
134
  apiKey: string;
@@ -39,7 +147,7 @@ interface ScanOptions {
39
147
  * { apiKey: process.env.AGENTVERIFY_API_KEY }
40
148
  * )
41
149
  *
42
- * result.verdict // 'VERIFIED' | 'NOT VERIFIED'
150
+ * result.verdict // 'VERIFIED' | 'NOT_VERIFIED' | 'NOT_ASSESSED'
43
151
  * result.riskScore // 0-100
44
152
  * result.findings // Array of findings
45
153
  */