@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
@@ -51,7 +51,7 @@ function hasMinimumAccess(actual, required) {
51
51
  }
52
52
 
53
53
  // src/version.ts
54
- var SDK_VERSION = "2.4.11";
54
+ var SDK_VERSION = "2.4.13";
55
55
 
56
56
  // src/verify.ts
57
57
  var DEFAULT_CONFIG = {
@@ -70,22 +70,27 @@ var DEFAULT_CONFIG = {
70
70
  };
71
71
  var initCheckPerformed = false;
72
72
  var deprecationWarningShown = false;
73
- async function performInitCheck(apiBaseUrl, debug) {
73
+ async function performInitCheck(apiBaseUrl, debug, strictInit) {
74
74
  initCheckPerformed = true;
75
75
  try {
76
76
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
77
77
  const response = await fetch(probeUrl, { method: "HEAD" });
78
78
  const contentType = response.headers.get("content-type") ?? "";
79
79
  if (contentType.startsWith("text/html")) {
80
- console.warn(
81
- `[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.`
82
- );
80
+ 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).`;
81
+ if (strictInit) {
82
+ throw new Error(`${message} (strictInit=true)`);
83
+ }
84
+ console.warn(`${message} Set disableInitChecks: true on GatewayConfig to silence.`);
83
85
  } else if (debug) {
84
86
  console.log(
85
87
  `[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
86
88
  );
87
89
  }
88
90
  } catch (err) {
91
+ if (strictInit) {
92
+ throw err;
93
+ }
89
94
  if (debug) {
90
95
  console.log(`[VerificationGateway] init check failed (non-blocking): ${String(err)}`);
91
96
  }
@@ -109,7 +114,23 @@ function getCacheKey(request) {
109
114
  request.counterpartyType || "",
110
115
  request.isSubAgentRequest ? "1" : "0",
111
116
  request.parentAgentId || "",
112
- request.subAgentDepth ?? ""
117
+ request.subAgentDepth ?? "",
118
+ // Audit F-A1-07: previously-missing dimensions that DO affect the
119
+ // backend verdict. Without these, two requests with different
120
+ // durations (e.g. 60s vs 86400s) collided on the same cache key and
121
+ // the shorter-duration allow served the longer-duration request.
122
+ request.durationRequired ?? "",
123
+ request.invocationProtocol || "",
124
+ request.enableRuntimeChallenge ? "1" : "0",
125
+ // callerMetadata fields contribute to risk model; include the ones
126
+ // backend reads. sourceIp/userAgent/forwardedFor change per-request
127
+ // so their inclusion effectively forces a re-check for any varying
128
+ // client (the right behavior — IP-driven anomaly scoring shouldn't
129
+ // be cached across IPs).
130
+ request.callerMetadata?.sourceIp || "",
131
+ request.callerMetadata?.userAgent || "",
132
+ request.callerMetadata?.forwardedFor || "",
133
+ request.callerMetadata?.agentCardUrl || ""
113
134
  ].join("|");
114
135
  }
115
136
  function getCachedResult(request) {
@@ -135,9 +156,13 @@ function cacheResult(request, result, configuredTtl) {
135
156
  }
136
157
  function extractCredentials(headers, query) {
137
158
  const credentials = {};
159
+ const ASTRA_ID_PATTERN = /^ASTRAE?-[A-Za-z0-9_-]{1,64}$/;
138
160
  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"];
139
161
  if (astraIdHeader) {
140
- credentials.astraId = Array.isArray(astraIdHeader) ? astraIdHeader[0] : astraIdHeader;
162
+ const raw = Array.isArray(astraIdHeader) ? astraIdHeader[0] : typeof astraIdHeader === "string" ? astraIdHeader : void 0;
163
+ if (typeof raw === "string" && ASTRA_ID_PATTERN.test(raw)) {
164
+ credentials.astraId = raw;
165
+ }
141
166
  }
142
167
  const apiKeyHeader = headers["x-api-key"] || headers["X-Api-Key"] || headers["X-API-KEY"];
143
168
  if (apiKeyHeader) {
@@ -146,9 +171,11 @@ function extractCredentials(headers, query) {
146
171
  const authHeader = headers["authorization"] || headers["Authorization"];
147
172
  if (authHeader) {
148
173
  const authValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;
149
- credentials.authorizationHeader = authValue;
150
- if (authValue.startsWith("Bearer ")) {
151
- credentials.jwt = authValue.slice(7);
174
+ if (typeof authValue === "string") {
175
+ credentials.authorizationHeader = authValue;
176
+ if (authValue.startsWith("Bearer ")) {
177
+ credentials.jwt = authValue.slice(7);
178
+ }
152
179
  }
153
180
  }
154
181
  if (query) {
@@ -166,7 +193,7 @@ function createGuidanceResponse(config, reason, options = {}) {
166
193
  const isApiError = source === "api_error";
167
194
  const guidance = isApiError ? {
168
195
  message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
169
- registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/register`,
196
+ registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/agents/register`,
170
197
  documentationUrl: `${config.apiBaseUrl.replace("/api", "")}/docs/agent-access`,
171
198
  steps: [
172
199
  "Retry the request with exponential backoff",
@@ -174,7 +201,7 @@ function createGuidanceResponse(config, reason, options = {}) {
174
201
  ]
175
202
  } : {
176
203
  message: "This service verifies AI agents before granting access. Please register your agent with AstraSync.",
177
- registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/register`,
204
+ registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/agents/register`,
178
205
  documentationUrl: `${config.apiBaseUrl.replace("/api", "")}/docs/agent-access`,
179
206
  steps: [
180
207
  "Register for an AstraSync account",
@@ -251,12 +278,8 @@ async function callVerifyAccessAPI(config, request) {
251
278
  "Content-Type": "application/json",
252
279
  ...config.customHeaders
253
280
  };
254
- if (credentials.authorizationHeader) {
255
- headers["Authorization"] = credentials.authorizationHeader;
256
- } else if (config.apiKey) {
257
- headers["Authorization"] = `Bearer ${config.apiKey}`;
258
- }
259
281
  if (config.apiKey) {
282
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
260
283
  headers["X-API-Key"] = config.apiKey;
261
284
  }
262
285
  try {
@@ -302,7 +325,11 @@ async function callVerifyAccessAPI(config, request) {
302
325
  async function verify(config, request) {
303
326
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
304
327
  if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
305
- void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug);
328
+ if (mergedConfig.strictInit) {
329
+ await performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, true);
330
+ } else {
331
+ void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, false);
332
+ }
306
333
  }
307
334
  if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
308
335
  deprecationWarningShown = true;
@@ -356,7 +383,7 @@ async function verify(config, request) {
356
383
  requiresApproval: apiResponse.access?.requiresApproval,
357
384
  guidance: {
358
385
  message: apiResponse.access?.reason || "Access denied by PDLSS policy",
359
- registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
386
+ registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/agents/register`,
360
387
  documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/pdlss`
361
388
  },
362
389
  verifiedAt: /* @__PURE__ */ new Date(),
@@ -426,13 +453,15 @@ async function verify(config, request) {
426
453
  result.denialReasons = result.recommendationReasons || [
427
454
  "Access denied by AstraSync recommendation"
428
455
  ];
429
- if (result.runtimeChallenge) {
430
- result.guidance = {
431
- message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
432
- registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
433
- documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/runtime-challenge`
434
- };
435
- }
456
+ result.guidance = result.runtimeChallenge ? {
457
+ message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
458
+ registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/agents/register`,
459
+ documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/runtime-challenge`
460
+ } : {
461
+ message: result.recommendationReasons?.[0] || "Access denied by AstraSync recommendation",
462
+ registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/agents/register`,
463
+ documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/pdlss`
464
+ };
436
465
  } else if (result.recommendation === "step_up_required") {
437
466
  result.requiresStepUp = true;
438
467
  if (ACCESS_LEVEL_HIERARCHY[result.accessLevel] > ACCESS_LEVEL_HIERARCHY["read-only"]) {
@@ -590,7 +619,7 @@ function mcpToPdlss(parsed, headerPurpose, headerAction) {
590
619
  action = parsed.actionFromBody;
591
620
  actionSource = parsed.actionSourceFromBody;
592
621
  } else {
593
- action = parsed.toolName ? `${parsed.method}:${parsed.toolName}` : parsed.method;
622
+ action = parsed.toolName ? parsed.method === "tools/call" ? parsed.toolName : `${parsed.method}:${parsed.toolName}` : parsed.method;
594
623
  actionSource = "transport_layer";
595
624
  }
596
625
  return { purpose, action, resource, purposeSource, actionSource };
@@ -609,6 +638,17 @@ function readSingleHeader(value) {
609
638
  if (Array.isArray(value)) return value[0];
610
639
  return void 0;
611
640
  }
641
+ function dedupeFailures(result) {
642
+ if (result.failures && result.failures.length > 1) {
643
+ const seen = /* @__PURE__ */ new Set();
644
+ result.failures = result.failures.filter((f) => {
645
+ const key = `${f.dimension}|${f.message}|${f.guidance ?? ""}`;
646
+ if (seen.has(key)) return false;
647
+ seen.add(key);
648
+ return true;
649
+ });
650
+ }
651
+ }
612
652
  function defaultMcpDenied(result, req, res) {
613
653
  const id = req.body?.id ?? null;
614
654
  const status = !result.identityVerified ? 401 : 403;
@@ -648,10 +688,11 @@ function createMcpMiddleware(options) {
648
688
  onAgentIdMismatch = "reject",
649
689
  skip = false,
650
690
  onDenied = defaultMcpDenied,
651
- trustVerifiedHop = true,
691
+ trustVerifiedHop = false,
652
692
  verifiedHopMaxAgeMs,
653
693
  recordDecisions,
654
694
  enableRuntimeChallenge = true,
695
+ failOnError = "open",
655
696
  ...config
656
697
  } = options;
657
698
  return async (req, res, next) => {
@@ -759,6 +800,7 @@ function createMcpMiddleware(options) {
759
800
  recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
760
801
  });
761
802
  }
803
+ dedupeFailures(result);
762
804
  onDenied(result, req, res);
763
805
  return;
764
806
  }
@@ -804,6 +846,7 @@ function createMcpMiddleware(options) {
804
846
  });
805
847
  }
806
848
  }
849
+ dedupeFailures(result);
807
850
  onDenied(result, req, res);
808
851
  return;
809
852
  }
@@ -827,7 +870,30 @@ function createMcpMiddleware(options) {
827
870
  }
828
871
  next();
829
872
  } catch (error) {
873
+ const errorClass = error instanceof Error ? error.constructor.name : typeof error;
874
+ const correlationId = req.headers["x-request-id"] || req.headers["x-correlation-id"] || `gen-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
830
875
  console.error("[VerificationGateway/MCP] Middleware error:", error);
876
+ console.warn(
877
+ `[SHADOW] would-have-denied: errorClass=${errorClass} route=${req.method}:${req.path} merchantId=${config.counterpartyId ?? "unknown"} correlationId=${correlationId}`
878
+ );
879
+ if (failOnError === "closed") {
880
+ const result = {
881
+ identityVerified: false,
882
+ policyAllowed: false,
883
+ accessLevel: "none",
884
+ denialReasons: [`MCP middleware internal error: ${errorClass}`],
885
+ failures: [
886
+ {
887
+ dimension: "middleware.internal_error",
888
+ message: `Middleware threw ${errorClass} \u2014 failing closed`
889
+ }
890
+ ],
891
+ verifiedAt: /* @__PURE__ */ new Date(),
892
+ correlationId
893
+ };
894
+ dedupeFailures(result);
895
+ return onDenied(result, req, res);
896
+ }
831
897
  next();
832
898
  }
833
899
  };