@astrasyncai/verification-gateway 3.1.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) 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 +46 -61
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +46 -61
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/mcp.d.mts +12 -7
  10. package/dist/adapters/mcp.d.ts +12 -7
  11. package/dist/adapters/mcp.js +60 -99
  12. package/dist/adapters/mcp.js.map +1 -1
  13. package/dist/adapters/mcp.mjs +60 -99
  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 +37 -30
  18. package/dist/adapters/nextjs.js.map +1 -1
  19. package/dist/adapters/nextjs.mjs +37 -30
  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 +25 -14
  24. package/dist/adapters/sdk.js.map +1 -1
  25. package/dist/adapters/sdk.mjs +25 -14
  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/browser/background.js +18 -21
  30. package/dist/browser/background.js.map +1 -1
  31. package/dist/browser/background.mjs +18 -21
  32. package/dist/browser/background.mjs.map +1 -1
  33. package/dist/browser/browser-adapter.d.mts +2 -2
  34. package/dist/browser/browser-adapter.d.ts +2 -2
  35. package/dist/cli/index.d.mts +2 -2
  36. package/dist/cli/index.d.ts +2 -2
  37. package/dist/cursor/cursor-adapter.d.mts +2 -2
  38. package/dist/cursor/cursor-adapter.d.ts +2 -2
  39. package/dist/cursor/extension.d.mts +2 -2
  40. package/dist/cursor/extension.d.ts +2 -2
  41. package/dist/cursor/extension.js +18 -21
  42. package/dist/cursor/extension.js.map +1 -1
  43. package/dist/cursor/extension.mjs +18 -21
  44. package/dist/cursor/extension.mjs.map +1 -1
  45. package/dist/{express-DavQ76oF.d.ts → express-BowlMHQF.d.ts} +1 -1
  46. package/dist/{express-DFVBlXr_.d.mts → express-CeoSdOAZ.d.mts} +1 -1
  47. package/dist/gateway/gateway.d.mts +2 -2
  48. package/dist/gateway/gateway.d.ts +2 -2
  49. package/dist/gateway/gateway.js +18 -21
  50. package/dist/gateway/gateway.js.map +1 -1
  51. package/dist/gateway/gateway.mjs +18 -21
  52. package/dist/gateway/gateway.mjs.map +1 -1
  53. package/dist/git-trigger/git-hooks.d.mts +2 -2
  54. package/dist/git-trigger/git-hooks.d.ts +2 -2
  55. package/dist/{index-BhL2R65s.d.mts → index-B51W8gn8.d.mts} +1 -1
  56. package/dist/{index-BhEgEiJL.d.ts → index-DBmlycVm.d.ts} +1 -1
  57. package/dist/{index-BVxantdv.d.mts → index-DtGziFEm.d.mts} +1 -1
  58. package/dist/{index-Dk2nIA4w.d.ts → index-DzXXBuLm.d.ts} +1 -1
  59. package/dist/index.d.mts +7 -7
  60. package/dist/index.d.ts +7 -7
  61. package/dist/index.js +87 -122
  62. package/dist/index.js.map +1 -1
  63. package/dist/index.mjs +87 -122
  64. package/dist/index.mjs.map +1 -1
  65. package/dist/local-evaluator/evaluator.d.mts +2 -2
  66. package/dist/local-evaluator/evaluator.d.ts +2 -2
  67. package/dist/{nextjs-D-maqrNz.d.mts → nextjs-BW1rzr1I.d.mts} +1 -1
  68. package/dist/{nextjs-BXLH1hJj.d.ts → nextjs-V_K0qlAQ.d.ts} +1 -1
  69. package/dist/{sdk-767LaEP8.d.mts → sdk-ZYgI7G9f.d.ts} +14 -3
  70. package/dist/{sdk-K8IgssHI.d.ts → sdk-e5jg7sqW.d.mts} +14 -3
  71. package/dist/transport/index.d.mts +2 -2
  72. package/dist/transport/index.d.ts +2 -2
  73. package/dist/{types-CyFwZ_Yu.d.mts → types-BNiLZY0i.d.mts} +1 -1
  74. package/dist/{types-WIRp_BP_.d.ts → types-DJi-u3fz.d.ts} +1 -1
  75. package/dist/{types-Cuh7ELfr.d.mts → types-rFh4VMH4.d.mts} +5 -2
  76. package/dist/{types-Cuh7ELfr.d.ts → types-rFh4VMH4.d.ts} +5 -2
  77. package/dist/ui/index.d.mts +1 -1
  78. package/dist/ui/index.d.ts +1 -1
  79. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -126,7 +126,7 @@ function getCapabilities(accessLevel) {
126
126
  }
127
127
 
128
128
  // src/version.ts
129
- var SDK_VERSION = "3.1.0";
129
+ var SDK_VERSION = "3.2.1";
130
130
 
131
131
  // src/well-known.ts
132
132
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -231,7 +231,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
231
231
  }
232
232
  }
233
233
  var verificationCache = /* @__PURE__ */ new Map();
234
- function getCacheKey(request) {
234
+ function getCacheKey(request, counterpartyId) {
235
235
  const c = request.credentials;
236
236
  return [
237
237
  c.astraId || "",
@@ -244,6 +244,14 @@ function getCacheKey(request) {
244
244
  request.jurisdiction || "",
245
245
  request.transactionValue ?? "",
246
246
  request.currency || "",
247
+ // SECURITY (cross-merchant cache leak): the merchant identity is sent via
248
+ // `config.counterpartyId`, NOT on the request, so it was previously absent
249
+ // from the key — two verifies for the SAME agent/purpose/action/value but
250
+ // DIFFERENT merchants collided, and a grant at a permissive merchant (low
251
+ // trust floor) was served for a stricter one. Same bug class as the
252
+ // duration omission (F-A1-07). counterpartyId affects the backend verdict
253
+ // (trust floor / per-route policy), so it MUST key the cache.
254
+ counterpartyId || "",
247
255
  request.counterpartyUrl || "",
248
256
  request.counterpartyType || "",
249
257
  request.isSubAgentRequest ? "1" : "0",
@@ -267,8 +275,8 @@ function getCacheKey(request) {
267
275
  request.callerMetadata?.agentCardUrl || ""
268
276
  ].join("|");
269
277
  }
270
- function getCachedResult(request) {
271
- const key = getCacheKey(request);
278
+ function getCachedResult(request, counterpartyId) {
279
+ const key = getCacheKey(request, counterpartyId);
272
280
  const cached = verificationCache.get(key);
273
281
  if (cached && cached.expiresAt > Date.now()) {
274
282
  return cached.result;
@@ -280,9 +288,9 @@ function getCachedResult(request) {
280
288
  }
281
289
  var DEFAULT_AUTONOMOUS_TTL_SECONDS = 60;
282
290
  var DEFAULT_STEP_UP_TTL_SECONDS = 300;
283
- function cacheResult(request, result, configuredTtl) {
291
+ function cacheResult(request, result, configuredTtl, counterpartyId) {
284
292
  const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : result.requiresStepUp ? DEFAULT_STEP_UP_TTL_SECONDS : DEFAULT_AUTONOMOUS_TTL_SECONDS;
285
- const key = getCacheKey(request);
293
+ const key = getCacheKey(request, counterpartyId);
286
294
  verificationCache.set(key, {
287
295
  result,
288
296
  expiresAt: Date.now() + ttlSeconds * 1e3
@@ -480,7 +488,7 @@ async function verify(config, request) {
480
488
  );
481
489
  }
482
490
  if (mergedConfig.cacheTtl !== 0) {
483
- const cached = getCachedResult(request);
491
+ const cached = getCachedResult(request, mergedConfig.counterpartyId);
484
492
  if (cached) {
485
493
  if (mergedConfig.debug) {
486
494
  console.log("[VerificationGateway] Returning cached result");
@@ -532,8 +540,8 @@ async function verify(config, request) {
532
540
  verifiedAt: /* @__PURE__ */ new Date(),
533
541
  // Extract sessionId so decisions can be recorded for denials too
534
542
  sessionId: apiResponse.sessionId,
535
- // v2.3.10 (defect #34, round-4): anonymous traffic has no session →
536
- // correlationId is the linking key for paired local_override events.
543
+ // Anonymous traffic has no session → correlationId is the per-attempt
544
+ // linking key (the sessionId-equivalent for anonymous callers).
537
545
  correlationId: apiResponse.correlationId,
538
546
  recommendation: apiResponse.recommendation,
539
547
  recommendationReasons: apiResponse.recommendationReasons
@@ -607,17 +615,14 @@ async function verify(config, request) {
607
615
  };
608
616
  } else if (result.recommendation === "step_up_required") {
609
617
  result.requiresStepUp = true;
610
- if (ACCESS_LEVEL_HIERARCHY[result.accessLevel] > ACCESS_LEVEL_HIERARCHY["read-only"]) {
611
- result.accessLevel = "read-only";
612
- }
613
618
  result.denialReasons = result.recommendationReasons || ["Step-up verification required"];
614
619
  }
615
620
  if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny") {
616
- cacheResult(request, result, mergedConfig.cacheTtl);
621
+ cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
617
622
  }
618
623
  return result;
619
624
  }
620
- async function recordDecision(config, sessionId, decision, reason, override) {
625
+ async function recordDecision(config, sessionId, decision, reason) {
621
626
  const headers = { "Content-Type": "application/json" };
622
627
  if (config.apiKey) {
623
628
  headers["Authorization"] = `Bearer ${config.apiKey}`;
@@ -626,36 +631,7 @@ async function recordDecision(config, sessionId, decision, reason, override) {
626
631
  await fetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
627
632
  method: "POST",
628
633
  headers,
629
- body: JSON.stringify({
630
- decision,
631
- reason,
632
- ...override && {
633
- overriddenBy: override.overriddenBy,
634
- toolName: override.toolName,
635
- requestedLevel: override.requestedLevel,
636
- grantedLevel: override.grantedLevel
637
- }
638
- })
639
- }).catch(() => {
640
- });
641
- }
642
- async function recordAnonymousLocalOverride(config, correlationId, override, reason) {
643
- const headers = { "Content-Type": "application/json" };
644
- if (config.apiKey) {
645
- headers["Authorization"] = `Bearer ${config.apiKey}`;
646
- headers["X-API-Key"] = config.apiKey;
647
- }
648
- await fetch(`${config.apiBaseUrl}/agents/verify-access/local-override`, {
649
- method: "POST",
650
- headers,
651
- body: JSON.stringify({
652
- correlationId,
653
- reason,
654
- overriddenBy: override.overriddenBy,
655
- toolName: override.toolName,
656
- requestedLevel: override.requestedLevel,
657
- grantedLevel: override.grantedLevel
658
- })
634
+ body: JSON.stringify({ decision, reason })
659
635
  }).catch(() => {
660
636
  });
661
637
  }
@@ -856,6 +832,19 @@ function resolveHttpPdlss(input) {
856
832
  return { purpose, action, purposeSource, actionSource };
857
833
  }
858
834
 
835
+ // src/adapters/approval-gate.ts
836
+ var APPROVAL_REASON = "Transaction is above the autonomous limit and requires human approval, which is not yet available \u2014 it cannot be completed automatically.";
837
+ function requiresHumanApproval(result) {
838
+ return result.requiresStepUp === true || result.requiresApproval === true;
839
+ }
840
+ function annotateApprovalRequired(result) {
841
+ result.failures = [
842
+ ...result.failures ?? [],
843
+ { dimension: "commerce.intent.approval_required", message: APPROVAL_REASON }
844
+ ];
845
+ result.denialReasons = [APPROVAL_REASON, ...result.denialReasons ?? []];
846
+ }
847
+
859
848
  // src/pdlss-pre-check.ts
860
849
  function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
861
850
  const failures = [];
@@ -1163,6 +1152,16 @@ function createMiddleware(options) {
1163
1152
  onDenied(result, req, res);
1164
1153
  return;
1165
1154
  }
1155
+ if (requiresHumanApproval(result)) {
1156
+ annotateApprovalRequired(result);
1157
+ if (shouldRecordDecisions && sessionId) {
1158
+ recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
1159
+ });
1160
+ }
1161
+ dedupeFailures(result);
1162
+ onDenied(result, req, res);
1163
+ return;
1164
+ }
1166
1165
  if (!shouldEnforce) {
1167
1166
  if (config.setPassThroughHeader) {
1168
1167
  res.setHeader("X-Astra-Gateway-Mode", "enforced");
@@ -1174,35 +1173,12 @@ function createMiddleware(options) {
1174
1173
  }
1175
1174
  return next();
1176
1175
  }
1177
- if (!hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
1178
- const insufficientFailure = {
1179
- dimension: "access_level.insufficient",
1180
- message: `Endpoint requires accessLevel '${routeConfig.minAccessLevel}'; agent has '${result.accessLevel}'.`,
1181
- guidance: "Request elevated access via step-up verification (coming soon \u2014 ships this month). Step-up lets the agent owner approve a one-time elevation for this specific counterparty + purpose without changing the agent's baseline trust score."
1182
- };
1183
- result.failures = [...result.failures ?? [], insufficientFailure];
1184
- result.denialReasons = [...result.denialReasons ?? [], insufficientFailure.message];
1185
- if (!result.guidance && wellKnownUrls) {
1186
- result.guidance = {
1187
- message: insufficientFailure.message,
1188
- registrationUrl: wellKnownUrls.registrationUrl,
1189
- documentationUrl: wellKnownUrls.documentationUrl
1190
- };
1191
- }
1192
- if (shouldRecordDecisions && sessionId) {
1193
- recordDecision(config, sessionId, "denied", insufficientFailure.message).catch(() => {
1194
- });
1195
- }
1196
- dedupeFailures(result);
1197
- onDenied(result, req, res);
1198
- return;
1199
- }
1200
1176
  if (routeConfig.minTrustScore && result.agent) {
1201
1177
  if (result.agent.trustScore < routeConfig.minTrustScore) {
1202
1178
  const trustFailure = {
1203
- dimension: "access_level.insufficient",
1204
- message: `Trust score ${result.agent.trustScore} is below required ${routeConfig.minTrustScore} for this route.`,
1205
- guidance: "Request elevated access via step-up verification (coming soon \u2014 ships this month). Step-up lets the agent owner approve a one-time elevation for this specific counterparty + purpose without changing the agent's baseline trust score."
1179
+ dimension: "endpoint.trust",
1180
+ message: "Trust below the route requirement for this endpoint.",
1181
+ guidance: "Trust is below this route's floor. Trust is not overridable \u2014 the agent either meets the endpoint's trust policy or it doesn't. Raise the agent's trust via real signals (KYD, blockchain registration, agent-card), or have the operator lower the route's minTrustScore."
1206
1182
  };
1207
1183
  result.failures = [...result.failures ?? [], trustFailure];
1208
1184
  result.denialReasons = [trustFailure.message];
@@ -1633,7 +1609,9 @@ function createMiddleware2(options) {
1633
1609
  agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0
1634
1610
  }
1635
1611
  });
1636
- if (!result.identityVerified || !result.policyAllowed || !hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
1612
+ const approvalRequired = result.identityVerified && result.policyAllowed && requiresHumanApproval(result);
1613
+ if (approvalRequired) annotateApprovalRequired(result);
1614
+ if (!result.identityVerified || !result.policyAllowed || approvalRequired) {
1637
1615
  if (pathname.startsWith("/api/")) {
1638
1616
  return NextResponse.json(
1639
1617
  {
@@ -1641,11 +1619,10 @@ function createMiddleware2(options) {
1641
1619
  error: {
1642
1620
  // Round-18 G4: 401 → identity missing (re-auth); 403 → identity
1643
1621
  // OK, policy denied (update PDLSS / step up).
1644
- code: !result.identityVerified ? "UNAUTHORIZED" : "INSUFFICIENT_ACCESS",
1622
+ code: !result.identityVerified ? "UNAUTHORIZED" : "POLICY_DENIED",
1645
1623
  message: result.denialReasons?.[0] || "Access denied",
1646
- accessLevel: result.accessLevel,
1647
- required: routeConfig.minAccessLevel,
1648
- guidance: result.guidance
1624
+ guidance: result.guidance,
1625
+ failures: result.failures
1649
1626
  }
1650
1627
  },
1651
1628
  { status: !result.identityVerified ? 401 : 403 }
@@ -1672,7 +1649,6 @@ function createMiddleware2(options) {
1672
1649
  response.headers.set("X-AstraSync-Access-Level", result.accessLevel);
1673
1650
  if (result.agent) {
1674
1651
  response.headers.set("X-AstraSync-Agent-Id", result.agent.astraId);
1675
- response.headers.set("X-AstraSync-Trust-Score", result.agent.trustScore.toString());
1676
1652
  }
1677
1653
  return response;
1678
1654
  };
@@ -1746,7 +1722,13 @@ var VerificationGatewayClient = class {
1746
1722
  return this.executeWithRetry(() => quickVerify(this.config, credentials));
1747
1723
  }
1748
1724
  /**
1749
- * Check if an agent has a specific access level
1725
+ * Check if an agent has a specific access level.
1726
+ *
1727
+ * @deprecated 3.2.0 — the access-level band is informational only; it no
1728
+ * longer gates in the middleware adapters (post-3.1.0 feedback #1). This
1729
+ * explicit opt-in query still works, but prefer gating on the server-side
1730
+ * policy decision (identity + policy + trust) or per-route `minTrustScore`.
1731
+ * Explicit per-route condition→constraint rules are the Phase-2 successor.
1750
1732
  */
1751
1733
  async hasAccess(credentials, requiredLevel) {
1752
1734
  const result = await this.quickVerify(credentials);
@@ -4593,7 +4575,6 @@ function createMcpMiddleware(options) {
4593
4575
  return next();
4594
4576
  }
4595
4577
  req.mcpRequest = parsed;
4596
- const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
4597
4578
  const headerRaw = req.headers["x-astra-id"] ?? req.headers["x-astra-agentid"];
4598
4579
  const headerAstraId = typeof headerRaw === "string" ? headerRaw : Array.isArray(headerRaw) ? headerRaw[0] : void 0;
4599
4580
  const bodyAstraId = parsed.agentIdFromBody;
@@ -4630,7 +4611,7 @@ function createMcpMiddleware(options) {
4630
4611
  return next();
4631
4612
  }
4632
4613
  }
4633
- const { level: minAccessLevel, source: gateSource } = resolveMinAccessLevel(parsed, {
4614
+ const { level: minAccessLevel } = resolveMinAccessLevel(parsed, {
4634
4615
  toolGates,
4635
4616
  methodGates
4636
4617
  });
@@ -4666,6 +4647,23 @@ function createMcpMiddleware(options) {
4666
4647
  resolved_action: pdlss.action
4667
4648
  });
4668
4649
  }
4650
+ if (!pdlss.purpose) {
4651
+ const id = req.body?.id ?? null;
4652
+ res.status(400).json({
4653
+ jsonrpc: "2.0",
4654
+ id,
4655
+ error: {
4656
+ code: -32602,
4657
+ message: "PDLSS_PURPOSE_REQUIRED",
4658
+ data: {
4659
+ dimension: "pdlss.purpose",
4660
+ detail: "This tool is access-gated but the call declared no PDLSS purpose. Supply a bare-category purpose via the X-Astra-Purpose header or params._meta.astrasync.purpose, or have the merchant set the tool\u2019s purpose in its toolGate config.",
4661
+ resolvedAction: pdlss.action
4662
+ }
4663
+ }
4664
+ });
4665
+ return;
4666
+ }
4669
4667
  const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get("host")}${req.path}`;
4670
4668
  const shouldRecordDecisions = recordDecisions !== false;
4671
4669
  const result = await verify(config, {
@@ -4689,7 +4687,6 @@ function createMcpMiddleware(options) {
4689
4687
  });
4690
4688
  req.agentVerification = result;
4691
4689
  const sessionId = result.sessionId;
4692
- const correlationId = result.correlationId;
4693
4690
  if (!result.identityVerified || !result.policyAllowed) {
4694
4691
  if (shouldRecordDecisions && sessionId) {
4695
4692
  recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
@@ -4699,6 +4696,16 @@ function createMcpMiddleware(options) {
4699
4696
  onDenied(result, req, res);
4700
4697
  return;
4701
4698
  }
4699
+ if (requiresHumanApproval(result)) {
4700
+ annotateApprovalRequired(result);
4701
+ if (shouldRecordDecisions && sessionId) {
4702
+ recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
4703
+ });
4704
+ }
4705
+ dedupeFailures2(result);
4706
+ onDenied(result, req, res);
4707
+ return;
4708
+ }
4702
4709
  if (!shouldEnforce) {
4703
4710
  if (config.setPassThroughHeader) {
4704
4711
  res.setHeader("X-Astra-Gateway-Mode", "enforced");
@@ -4710,48 +4717,6 @@ function createMcpMiddleware(options) {
4710
4717
  }
4711
4718
  return next();
4712
4719
  }
4713
- if (!hasMinimumAccess(result.accessLevel, minAccessLevel)) {
4714
- const insufficientFailure = {
4715
- dimension: "access_level.insufficient",
4716
- message: `Tool requires accessLevel '${minAccessLevel}'; agent has '${result.accessLevel}'.`,
4717
- guidance: "Request elevated access via step-up verification (coming soon \u2014 ships this month). Step-up lets the agent owner approve a one-time elevation for this specific counterparty + purpose without changing the agent's baseline trust score."
4718
- };
4719
- result.failures = [...result.failures ?? [], insufficientFailure];
4720
- result.denialReasons = [...result.denialReasons ?? [], insufficientFailure.message];
4721
- if (!result.guidance && wellKnownUrls) {
4722
- result.guidance = {
4723
- message: insufficientFailure.message,
4724
- registrationUrl: wellKnownUrls.registrationUrl,
4725
- documentationUrl: wellKnownUrls.documentationUrl
4726
- };
4727
- }
4728
- if (shouldRecordDecisions) {
4729
- const overrideKind = gateSource === "toolGate" ? "toolGate" : gateSource === "methodGate" ? "methodGate" : "other";
4730
- const override = {
4731
- overriddenBy: overrideKind,
4732
- ...parsed.toolName && { toolName: parsed.toolName },
4733
- requestedLevel: minAccessLevel,
4734
- grantedLevel: result.accessLevel
4735
- };
4736
- if (sessionId) {
4737
- recordDecision(config, sessionId, "denied", result.denialReasons?.[0], override).catch(
4738
- () => {
4739
- }
4740
- );
4741
- } else if (correlationId) {
4742
- recordAnonymousLocalOverride(
4743
- config,
4744
- correlationId,
4745
- override,
4746
- result.denialReasons?.[0]
4747
- ).catch(() => {
4748
- });
4749
- }
4750
- }
4751
- dedupeFailures2(result);
4752
- onDenied(result, req, res);
4753
- return;
4754
- }
4755
4720
  if (effectiveAstraId) {
4756
4721
  res.setHeader(
4757
4722
  MCP_VERIFIED_HOP_HEADER,