@astrasyncai/verification-gateway 2.4.11 → 2.4.14

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 (91) hide show
  1. package/dist/adapter-interface/interface.d.mts +2 -2
  2. package/dist/adapter-interface/interface.d.ts +2 -2
  3. package/dist/adapters/express.d.mts +2 -2
  4. package/dist/adapters/express.d.ts +2 -2
  5. package/dist/adapters/express.js +129 -36
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +129 -36
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/mcp.d.mts +26 -4
  10. package/dist/adapters/mcp.d.ts +26 -4
  11. package/dist/adapters/mcp.js +94 -28
  12. package/dist/adapters/mcp.js.map +1 -1
  13. package/dist/adapters/mcp.mjs +94 -28
  14. package/dist/adapters/mcp.mjs.map +1 -1
  15. package/dist/adapters/nextjs.d.mts +2 -2
  16. package/dist/adapters/nextjs.d.ts +2 -2
  17. package/dist/adapters/nextjs.js +75 -29
  18. package/dist/adapters/nextjs.js.map +1 -1
  19. package/dist/adapters/nextjs.mjs +75 -29
  20. package/dist/adapters/nextjs.mjs.map +1 -1
  21. package/dist/adapters/sdk.d.mts +2 -2
  22. package/dist/adapters/sdk.d.ts +2 -2
  23. package/dist/adapters/sdk.js +45 -22
  24. package/dist/adapters/sdk.js.map +1 -1
  25. package/dist/adapters/sdk.mjs +45 -22
  26. package/dist/adapters/sdk.mjs.map +1 -1
  27. package/dist/agent/index.d.mts +2 -2
  28. package/dist/agent/index.d.ts +2 -2
  29. package/dist/agent/index.js +29 -0
  30. package/dist/agent/index.js.map +1 -1
  31. package/dist/agent/index.mjs +29 -0
  32. package/dist/agent/index.mjs.map +1 -1
  33. package/dist/browser/background.js +86 -24
  34. package/dist/browser/background.js.map +1 -1
  35. package/dist/browser/background.mjs +86 -24
  36. package/dist/browser/background.mjs.map +1 -1
  37. package/dist/browser/browser-adapter.d.mts +2 -2
  38. package/dist/browser/browser-adapter.d.ts +2 -2
  39. package/dist/cli/index.d.mts +2 -2
  40. package/dist/cli/index.d.ts +2 -2
  41. package/dist/cursor/cursor-adapter.d.mts +2 -2
  42. package/dist/cursor/cursor-adapter.d.ts +2 -2
  43. package/dist/cursor/extension.d.mts +2 -2
  44. package/dist/cursor/extension.d.ts +2 -2
  45. package/dist/cursor/extension.js +86 -24
  46. package/dist/cursor/extension.js.map +1 -1
  47. package/dist/cursor/extension.mjs +86 -24
  48. package/dist/cursor/extension.mjs.map +1 -1
  49. package/dist/{express-C1ePFB7n.d.ts → express-CrfwoNAR.d.ts} +1 -1
  50. package/dist/{express-4WStX3PV.d.mts → express-ienhAXps.d.mts} +1 -1
  51. package/dist/gateway/gateway.d.mts +2 -2
  52. package/dist/gateway/gateway.d.ts +2 -2
  53. package/dist/gateway/gateway.js +86 -24
  54. package/dist/gateway/gateway.js.map +1 -1
  55. package/dist/gateway/gateway.mjs +86 -24
  56. package/dist/gateway/gateway.mjs.map +1 -1
  57. package/dist/git-trigger/git-hooks.d.mts +2 -2
  58. package/dist/git-trigger/git-hooks.d.ts +2 -2
  59. package/dist/{index-ChPX4WHl.d.mts → index-B5e2IDWU.d.mts} +1 -1
  60. package/dist/{index-CzJMCgEy.d.ts → index-CCdZxvAr.d.ts} +71 -6
  61. package/dist/{index-D8IEntil.d.mts → index-CEg_WG6y.d.mts} +71 -6
  62. package/dist/{index-Cjm-zBeZ.d.ts → index-DC5f8eoQ.d.ts} +1 -1
  63. package/dist/index.d.mts +7 -7
  64. package/dist/index.d.ts +7 -7
  65. package/dist/index.js +344 -73
  66. package/dist/index.js.map +1 -1
  67. package/dist/index.mjs +344 -73
  68. package/dist/index.mjs.map +1 -1
  69. package/dist/local-evaluator/evaluator.d.mts +2 -2
  70. package/dist/local-evaluator/evaluator.d.ts +2 -2
  71. package/dist/local-evaluator/evaluator.js +12 -2
  72. package/dist/local-evaluator/evaluator.js.map +1 -1
  73. package/dist/local-evaluator/evaluator.mjs +12 -2
  74. package/dist/local-evaluator/evaluator.mjs.map +1 -1
  75. package/dist/{nextjs-BIORS__0.d.ts → nextjs-66R1KW8e.d.ts} +1 -1
  76. package/dist/{nextjs-CjzHdaXA.d.mts → nextjs-DSpisQst.d.mts} +1 -1
  77. package/dist/{sdk-Chhz-FcT.d.mts → sdk-5U_CBRpr.d.mts} +1 -1
  78. package/dist/{sdk-CqTEQAc6.d.ts → sdk-Bm8np66n.d.ts} +1 -1
  79. package/dist/transport/index.d.mts +2 -2
  80. package/dist/transport/index.d.ts +2 -2
  81. package/dist/transport/index.js +146 -28
  82. package/dist/transport/index.js.map +1 -1
  83. package/dist/transport/index.mjs +146 -28
  84. package/dist/transport/index.mjs.map +1 -1
  85. package/dist/{types-L15pYd2c.d.mts → types-B3USs-Kx.d.mts} +42 -1
  86. package/dist/{types-L15pYd2c.d.ts → types-B3USs-Kx.d.ts} +42 -1
  87. package/dist/{types-DNK2BgIf.d.mts → types-CgDCUfo8.d.mts} +1 -1
  88. package/dist/{types-DoWIuzfj.d.ts → types-R5N4ET6x.d.ts} +1 -1
  89. package/dist/ui/index.d.mts +1 -1
  90. package/dist/ui/index.d.ts +1 -1
  91. package/package.json +1 -1
@@ -18,7 +18,7 @@ function hasMinimumAccess(actual, required) {
18
18
  }
19
19
 
20
20
  // src/version.ts
21
- var SDK_VERSION = "2.4.11";
21
+ var SDK_VERSION = "2.4.13";
22
22
 
23
23
  // src/verify.ts
24
24
  var DEFAULT_CONFIG = {
@@ -37,22 +37,27 @@ var DEFAULT_CONFIG = {
37
37
  };
38
38
  var initCheckPerformed = false;
39
39
  var deprecationWarningShown = false;
40
- async function performInitCheck(apiBaseUrl, debug) {
40
+ async function performInitCheck(apiBaseUrl, debug, strictInit) {
41
41
  initCheckPerformed = true;
42
42
  try {
43
43
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
44
44
  const response = await fetch(probeUrl, { method: "HEAD" });
45
45
  const contentType = response.headers.get("content-type") ?? "";
46
46
  if (contentType.startsWith("text/html")) {
47
- console.warn(
48
- `[VerificationGateway] apiBaseUrl '${apiBaseUrl}' returned HTML (content-type: ${contentType}). This usually means apiBaseUrl is pointing at a marketing site instead of the API. Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging). Set disableInitChecks: true on GatewayConfig to silence this warning.`
49
- );
47
+ const message = `[VerificationGateway] apiBaseUrl '${apiBaseUrl}' returned HTML (content-type: ${contentType}). This usually means apiBaseUrl is pointing at a marketing site instead of the API. Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging).`;
48
+ if (strictInit) {
49
+ throw new Error(`${message} (strictInit=true)`);
50
+ }
51
+ console.warn(`${message} Set disableInitChecks: true on GatewayConfig to silence.`);
50
52
  } else if (debug) {
51
53
  console.log(
52
54
  `[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
53
55
  );
54
56
  }
55
57
  } catch (err) {
58
+ if (strictInit) {
59
+ throw err;
60
+ }
56
61
  if (debug) {
57
62
  console.log(`[VerificationGateway] init check failed (non-blocking): ${String(err)}`);
58
63
  }
@@ -76,7 +81,23 @@ function getCacheKey(request) {
76
81
  request.counterpartyType || "",
77
82
  request.isSubAgentRequest ? "1" : "0",
78
83
  request.parentAgentId || "",
79
- request.subAgentDepth ?? ""
84
+ request.subAgentDepth ?? "",
85
+ // Audit F-A1-07: previously-missing dimensions that DO affect the
86
+ // backend verdict. Without these, two requests with different
87
+ // durations (e.g. 60s vs 86400s) collided on the same cache key and
88
+ // the shorter-duration allow served the longer-duration request.
89
+ request.durationRequired ?? "",
90
+ request.invocationProtocol || "",
91
+ request.enableRuntimeChallenge ? "1" : "0",
92
+ // callerMetadata fields contribute to risk model; include the ones
93
+ // backend reads. sourceIp/userAgent/forwardedFor change per-request
94
+ // so their inclusion effectively forces a re-check for any varying
95
+ // client (the right behavior — IP-driven anomaly scoring shouldn't
96
+ // be cached across IPs).
97
+ request.callerMetadata?.sourceIp || "",
98
+ request.callerMetadata?.userAgent || "",
99
+ request.callerMetadata?.forwardedFor || "",
100
+ request.callerMetadata?.agentCardUrl || ""
80
101
  ].join("|");
81
102
  }
82
103
  function getCachedResult(request) {
@@ -102,9 +123,13 @@ function cacheResult(request, result, configuredTtl) {
102
123
  }
103
124
  function extractCredentials(headers, query) {
104
125
  const credentials = {};
126
+ const ASTRA_ID_PATTERN = /^ASTRAE?-[A-Za-z0-9_-]{1,64}$/;
105
127
  const astraIdHeader = headers["x-astra-id"] || headers["X-Astra-Id"] || headers["X-ASTRA-ID"] || headers["x-astra-agentid"] || headers["X-Astra-AgentId"] || headers["x-astra-agent-id"] || headers["X-Astra-Agent-Id"] || headers["X-ASTRA-AGENT-ID"];
106
128
  if (astraIdHeader) {
107
- credentials.astraId = Array.isArray(astraIdHeader) ? astraIdHeader[0] : astraIdHeader;
129
+ const raw = Array.isArray(astraIdHeader) ? astraIdHeader[0] : typeof astraIdHeader === "string" ? astraIdHeader : void 0;
130
+ if (typeof raw === "string" && ASTRA_ID_PATTERN.test(raw)) {
131
+ credentials.astraId = raw;
132
+ }
108
133
  }
109
134
  const apiKeyHeader = headers["x-api-key"] || headers["X-Api-Key"] || headers["X-API-KEY"];
110
135
  if (apiKeyHeader) {
@@ -113,9 +138,11 @@ function extractCredentials(headers, query) {
113
138
  const authHeader = headers["authorization"] || headers["Authorization"];
114
139
  if (authHeader) {
115
140
  const authValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;
116
- credentials.authorizationHeader = authValue;
117
- if (authValue.startsWith("Bearer ")) {
118
- credentials.jwt = authValue.slice(7);
141
+ if (typeof authValue === "string") {
142
+ credentials.authorizationHeader = authValue;
143
+ if (authValue.startsWith("Bearer ")) {
144
+ credentials.jwt = authValue.slice(7);
145
+ }
119
146
  }
120
147
  }
121
148
  if (query) {
@@ -133,7 +160,7 @@ function createGuidanceResponse(config, reason, options = {}) {
133
160
  const isApiError = source === "api_error";
134
161
  const guidance = isApiError ? {
135
162
  message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
136
- registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/register`,
163
+ registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/agents/register`,
137
164
  documentationUrl: `${config.apiBaseUrl.replace("/api", "")}/docs/agent-access`,
138
165
  steps: [
139
166
  "Retry the request with exponential backoff",
@@ -141,7 +168,7 @@ function createGuidanceResponse(config, reason, options = {}) {
141
168
  ]
142
169
  } : {
143
170
  message: "This service verifies AI agents before granting access. Please register your agent with AstraSync.",
144
- registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/register`,
171
+ registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/agents/register`,
145
172
  documentationUrl: `${config.apiBaseUrl.replace("/api", "")}/docs/agent-access`,
146
173
  steps: [
147
174
  "Register for an AstraSync account",
@@ -218,12 +245,8 @@ async function callVerifyAccessAPI(config, request) {
218
245
  "Content-Type": "application/json",
219
246
  ...config.customHeaders
220
247
  };
221
- if (credentials.authorizationHeader) {
222
- headers["Authorization"] = credentials.authorizationHeader;
223
- } else if (config.apiKey) {
224
- headers["Authorization"] = `Bearer ${config.apiKey}`;
225
- }
226
248
  if (config.apiKey) {
249
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
227
250
  headers["X-API-Key"] = config.apiKey;
228
251
  }
229
252
  try {
@@ -269,7 +292,11 @@ async function callVerifyAccessAPI(config, request) {
269
292
  async function verify(config, request) {
270
293
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
271
294
  if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
272
- void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug);
295
+ if (mergedConfig.strictInit) {
296
+ await performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, true);
297
+ } else {
298
+ void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, false);
299
+ }
273
300
  }
274
301
  if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
275
302
  deprecationWarningShown = true;
@@ -323,7 +350,7 @@ async function verify(config, request) {
323
350
  requiresApproval: apiResponse.access?.requiresApproval,
324
351
  guidance: {
325
352
  message: apiResponse.access?.reason || "Access denied by PDLSS policy",
326
- registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
353
+ registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/agents/register`,
327
354
  documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/pdlss`
328
355
  },
329
356
  verifiedAt: /* @__PURE__ */ new Date(),
@@ -393,13 +420,15 @@ async function verify(config, request) {
393
420
  result.denialReasons = result.recommendationReasons || [
394
421
  "Access denied by AstraSync recommendation"
395
422
  ];
396
- if (result.runtimeChallenge) {
397
- result.guidance = {
398
- message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
399
- registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
400
- documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/runtime-challenge`
401
- };
402
- }
423
+ result.guidance = result.runtimeChallenge ? {
424
+ message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
425
+ registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/agents/register`,
426
+ documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/runtime-challenge`
427
+ } : {
428
+ message: result.recommendationReasons?.[0] || "Access denied by AstraSync recommendation",
429
+ registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/agents/register`,
430
+ documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/pdlss`
431
+ };
403
432
  } else if (result.recommendation === "step_up_required") {
404
433
  result.requiresStepUp = true;
405
434
  if (ACCESS_LEVEL_HIERARCHY[result.accessLevel] > ACCESS_LEVEL_HIERARCHY["read-only"]) {
@@ -557,7 +586,7 @@ function mcpToPdlss(parsed, headerPurpose, headerAction) {
557
586
  action = parsed.actionFromBody;
558
587
  actionSource = parsed.actionSourceFromBody;
559
588
  } else {
560
- action = parsed.toolName ? `${parsed.method}:${parsed.toolName}` : parsed.method;
589
+ action = parsed.toolName ? parsed.method === "tools/call" ? parsed.toolName : `${parsed.method}:${parsed.toolName}` : parsed.method;
561
590
  actionSource = "transport_layer";
562
591
  }
563
592
  return { purpose, action, resource, purposeSource, actionSource };
@@ -576,6 +605,17 @@ function readSingleHeader(value) {
576
605
  if (Array.isArray(value)) return value[0];
577
606
  return void 0;
578
607
  }
608
+ function dedupeFailures(result) {
609
+ if (result.failures && result.failures.length > 1) {
610
+ const seen = /* @__PURE__ */ new Set();
611
+ result.failures = result.failures.filter((f) => {
612
+ const key = `${f.dimension}|${f.message}|${f.guidance ?? ""}`;
613
+ if (seen.has(key)) return false;
614
+ seen.add(key);
615
+ return true;
616
+ });
617
+ }
618
+ }
579
619
  function defaultMcpDenied(result, req, res) {
580
620
  const id = req.body?.id ?? null;
581
621
  const status = !result.identityVerified ? 401 : 403;
@@ -615,10 +655,11 @@ function createMcpMiddleware(options) {
615
655
  onAgentIdMismatch = "reject",
616
656
  skip = false,
617
657
  onDenied = defaultMcpDenied,
618
- trustVerifiedHop = true,
658
+ trustVerifiedHop = false,
619
659
  verifiedHopMaxAgeMs,
620
660
  recordDecisions,
621
661
  enableRuntimeChallenge = true,
662
+ failOnError = "open",
622
663
  ...config
623
664
  } = options;
624
665
  return async (req, res, next) => {
@@ -726,6 +767,7 @@ function createMcpMiddleware(options) {
726
767
  recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
727
768
  });
728
769
  }
770
+ dedupeFailures(result);
729
771
  onDenied(result, req, res);
730
772
  return;
731
773
  }
@@ -771,6 +813,7 @@ function createMcpMiddleware(options) {
771
813
  });
772
814
  }
773
815
  }
816
+ dedupeFailures(result);
774
817
  onDenied(result, req, res);
775
818
  return;
776
819
  }
@@ -794,7 +837,30 @@ function createMcpMiddleware(options) {
794
837
  }
795
838
  next();
796
839
  } catch (error) {
840
+ const errorClass = error instanceof Error ? error.constructor.name : typeof error;
841
+ const correlationId = req.headers["x-request-id"] || req.headers["x-correlation-id"] || `gen-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
797
842
  console.error("[VerificationGateway/MCP] Middleware error:", error);
843
+ console.warn(
844
+ `[SHADOW] would-have-denied: errorClass=${errorClass} route=${req.method}:${req.path} merchantId=${config.counterpartyId ?? "unknown"} correlationId=${correlationId}`
845
+ );
846
+ if (failOnError === "closed") {
847
+ const result = {
848
+ identityVerified: false,
849
+ policyAllowed: false,
850
+ accessLevel: "none",
851
+ denialReasons: [`MCP middleware internal error: ${errorClass}`],
852
+ failures: [
853
+ {
854
+ dimension: "middleware.internal_error",
855
+ message: `Middleware threw ${errorClass} \u2014 failing closed`
856
+ }
857
+ ],
858
+ verifiedAt: /* @__PURE__ */ new Date(),
859
+ correlationId
860
+ };
861
+ dedupeFailures(result);
862
+ return onDenied(result, req, res);
863
+ }
798
864
  next();
799
865
  }
800
866
  };