@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.
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +46 -61
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +46 -61
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +12 -7
- package/dist/adapters/mcp.d.ts +12 -7
- package/dist/adapters/mcp.js +60 -99
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +60 -99
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +37 -30
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +37 -30
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +25 -14
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +25 -14
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- package/dist/browser/background.js +18 -21
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +18 -21
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +2 -2
- package/dist/browser/browser-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/cursor/cursor-adapter.d.mts +2 -2
- package/dist/cursor/cursor-adapter.d.ts +2 -2
- package/dist/cursor/extension.d.mts +2 -2
- package/dist/cursor/extension.d.ts +2 -2
- package/dist/cursor/extension.js +18 -21
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +18 -21
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/{express-DavQ76oF.d.ts → express-BowlMHQF.d.ts} +1 -1
- package/dist/{express-DFVBlXr_.d.mts → express-CeoSdOAZ.d.mts} +1 -1
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +18 -21
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +18 -21
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +2 -2
- package/dist/git-trigger/git-hooks.d.ts +2 -2
- package/dist/{index-BhL2R65s.d.mts → index-B51W8gn8.d.mts} +1 -1
- package/dist/{index-BhEgEiJL.d.ts → index-DBmlycVm.d.ts} +1 -1
- package/dist/{index-BVxantdv.d.mts → index-DtGziFEm.d.mts} +1 -1
- package/dist/{index-Dk2nIA4w.d.ts → index-DzXXBuLm.d.ts} +1 -1
- package/dist/index.d.mts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +87 -122
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +87 -122
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/{nextjs-D-maqrNz.d.mts → nextjs-BW1rzr1I.d.mts} +1 -1
- package/dist/{nextjs-BXLH1hJj.d.ts → nextjs-V_K0qlAQ.d.ts} +1 -1
- package/dist/{sdk-767LaEP8.d.mts → sdk-ZYgI7G9f.d.ts} +14 -3
- package/dist/{sdk-K8IgssHI.d.ts → sdk-e5jg7sqW.d.mts} +14 -3
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/{types-CyFwZ_Yu.d.mts → types-BNiLZY0i.d.mts} +1 -1
- package/dist/{types-WIRp_BP_.d.ts → types-DJi-u3fz.d.ts} +1 -1
- package/dist/{types-Cuh7ELfr.d.mts → types-rFh4VMH4.d.mts} +5 -2
- package/dist/{types-Cuh7ELfr.d.ts → types-rFh4VMH4.d.ts} +5 -2
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- 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
|
|
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
|
-
//
|
|
536
|
-
//
|
|
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
|
|
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: "
|
|
1204
|
-
message:
|
|
1205
|
-
guidance: "
|
|
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
|
-
|
|
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" : "
|
|
1622
|
+
code: !result.identityVerified ? "UNAUTHORIZED" : "POLICY_DENIED",
|
|
1645
1623
|
message: result.denialReasons?.[0] || "Access denied",
|
|
1646
|
-
|
|
1647
|
-
|
|
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
|
|
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,
|