@astrasyncai/verification-gateway 5.11.0 → 5.12.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/README.md +4 -0
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +359 -30
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +359 -30
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +5 -1
- package/dist/adapters/mcp.d.ts +5 -1
- package/dist/adapters/mcp.js +168 -41
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +168 -41
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +1 -1
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +352 -13
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +352 -13
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +9 -1
- package/dist/adapters/sdk.d.ts +9 -1
- package/dist/adapters/sdk.js +100 -8
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +100 -8
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +284 -7
- package/dist/bin/astrasync-codex-hook.js +284 -7
- package/dist/bin/astrasync-guard.js +284 -7
- package/dist/bin/astrasync.js +297 -9
- package/dist/browser/background.js +284 -7
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +284 -7
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.js +284 -7
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +284 -7
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +284 -7
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +284 -7
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +1 -1
- package/dist/edge-config.d.ts +1 -1
- package/dist/edge-config.js +1 -1
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +128 -13
- package/dist/edge-core/index.d.ts +128 -13
- package/dist/edge-core/index.js +337 -55
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +334 -55
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +284 -7
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +284 -7
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +1 -1
- package/dist/git-trigger/git-hooks.d.ts +1 -1
- package/dist/index.d.mts +118 -5
- package/dist/index.d.ts +118 -5
- package/dist/index.js +486 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +480 -63
- package/dist/index.mjs.map +1 -1
- package/dist/platform-signatures.js +4 -1
- package/dist/platform-signatures.js.map +1 -1
- package/dist/platform-signatures.mjs +4 -1
- package/dist/platform-signatures.mjs.map +1 -1
- package/dist/registration/index.js +1 -1
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.js +1 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-CTmUpNpS.d.mts → types-BCkwBA84.d.mts} +12 -0
- package/dist/{types-CTmUpNpS.d.ts → types-BCkwBA84.d.ts} +12 -0
- package/dist/{types-CtFXmDzm.d.ts → types-C_b4QTyO.d.ts} +18 -0
- package/dist/{types-DQrn_kei.d.mts → types-DlshIIR-.d.mts} +18 -0
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +35 -4
- package/dist/verify.d.ts +35 -4
- package/dist/verify.js +130 -16
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +129 -16
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/dist/adapters/mcp.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var SDK_VERSION = "5.
|
|
2
|
+
var SDK_VERSION = "5.12.0";
|
|
3
3
|
|
|
4
4
|
// src/http.ts
|
|
5
5
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -69,23 +69,58 @@ function prefetchWellKnown(apiBaseUrl) {
|
|
|
69
69
|
inflight.set(apiBaseUrl, promise);
|
|
70
70
|
return promise;
|
|
71
71
|
}
|
|
72
|
-
async function getWellKnownUrls(apiBaseUrl) {
|
|
73
|
-
const entry = cache.get(apiBaseUrl);
|
|
74
|
-
if (entry) {
|
|
75
|
-
if (Date.now() - entry.fetchedAt > CACHE_TTL_MS) {
|
|
76
|
-
prefetchWellKnown(apiBaseUrl).catch(() => {
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
return entry.data;
|
|
80
|
-
}
|
|
81
|
-
const pending = inflight.get(apiBaseUrl);
|
|
82
|
-
if (pending) return pending;
|
|
83
|
-
return prefetchWellKnown(apiBaseUrl);
|
|
84
|
-
}
|
|
85
72
|
function getCachedWellKnownUrls(apiBaseUrl) {
|
|
86
73
|
return cache.get(apiBaseUrl)?.data;
|
|
87
74
|
}
|
|
88
75
|
|
|
76
|
+
// src/failure-posture.ts
|
|
77
|
+
var VERIFICATION_STATUS_HEADER = "X-Astra-Verification";
|
|
78
|
+
var DEFAULT_UNAVAILABLE_RETRY_AFTER_S = 30;
|
|
79
|
+
var REJECTED_IDENTITY_DIMENSIONS = /* @__PURE__ */ new Set([
|
|
80
|
+
"identity.invalid_agent_id",
|
|
81
|
+
"identity.unknown_agent",
|
|
82
|
+
"agent.lookup"
|
|
83
|
+
]);
|
|
84
|
+
var UNKNOWN_AGENT_GUIDANCE = "Register your agent with AstraSync (or, inside an MCP host, add the AstraSync MCP connector for keyless, human-approved registration), then present the canonical ASTRA-* id issued after owner approval.";
|
|
85
|
+
var UNAVAILABLE_DIMENSIONS = /* @__PURE__ */ new Set([
|
|
86
|
+
"verify_access.api_error",
|
|
87
|
+
"middleware.internal_error"
|
|
88
|
+
]);
|
|
89
|
+
function isVerificationUnavailable(result) {
|
|
90
|
+
if (result.misconfigured) return false;
|
|
91
|
+
return (result.failures ?? []).some((f) => UNAVAILABLE_DIMENSIONS.has(f.dimension));
|
|
92
|
+
}
|
|
93
|
+
function unavailableRetryAfterSeconds(result) {
|
|
94
|
+
if (typeof result.retryAfterMs === "number" && Number.isFinite(result.retryAfterMs)) {
|
|
95
|
+
return Math.max(1, Math.ceil(result.retryAfterMs / 1e3));
|
|
96
|
+
}
|
|
97
|
+
return DEFAULT_UNAVAILABLE_RETRY_AFTER_S;
|
|
98
|
+
}
|
|
99
|
+
function buildVerificationUnavailableBody(result) {
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
error: {
|
|
103
|
+
code: "VERIFICATION_UNAVAILABLE",
|
|
104
|
+
message: "Agent verification is temporarily unavailable and this path enforces verification. Your identity was not evaluated and no denial was recorded \u2014 retry after the Retry-After interval.",
|
|
105
|
+
retryable: true,
|
|
106
|
+
retryAfterSeconds: unavailableRetryAfterSeconds(result),
|
|
107
|
+
...result.failures && { failures: result.failures },
|
|
108
|
+
...result.correlationId && { correlationId: result.correlationId },
|
|
109
|
+
guidance: {
|
|
110
|
+
message: "Retry the request after the Retry-After interval, with exponential backoff; the condition is transient."
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function isRejectedIdentityClaim(result) {
|
|
116
|
+
return (result.failures ?? []).some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
|
|
117
|
+
}
|
|
118
|
+
function denyStatusFor(result, policyDeniedCode) {
|
|
119
|
+
if (isRejectedIdentityClaim(result)) return { status: 403, code: "AGENT_IDENTITY_REJECTED" };
|
|
120
|
+
if (result.identityVerified) return { status: 403, code: policyDeniedCode };
|
|
121
|
+
return { status: 401, code: "UNAUTHORIZED" };
|
|
122
|
+
}
|
|
123
|
+
|
|
89
124
|
// src/verify.ts
|
|
90
125
|
var DEFAULT_CONFIG = {
|
|
91
126
|
apiBaseUrl: "https://astrasync.ai/api",
|
|
@@ -331,11 +366,44 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
331
366
|
// coercing the absent recommendation to a policy 'deny'. Misconfig is
|
|
332
367
|
// deterministic and intentionally NOT marked retryable.
|
|
333
368
|
...isApiError && { retryable: true },
|
|
369
|
+
...options.httpStatus !== void 0 && { httpStatus: options.httpStatus },
|
|
370
|
+
...options.retryAfterMs !== void 0 && { retryAfterMs: options.retryAfterMs },
|
|
334
371
|
correlationId: options.correlationId,
|
|
335
372
|
attemptId: options.attemptId,
|
|
336
373
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
337
374
|
};
|
|
338
375
|
}
|
|
376
|
+
async function readJsonSafe(response) {
|
|
377
|
+
try {
|
|
378
|
+
const parsed = await response.json();
|
|
379
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
380
|
+
} catch {
|
|
381
|
+
return {};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function rejectedIdentityGuidance(failures) {
|
|
385
|
+
const f = failures?.find((x) => REJECTED_IDENTITY_DIMENSIONS.has(x.dimension));
|
|
386
|
+
if (!f) return void 0;
|
|
387
|
+
if (f.dimension === "agent.lookup") {
|
|
388
|
+
return `The presented agent identifier is not registered with AstraSync. ${UNKNOWN_AGENT_GUIDANCE}`;
|
|
389
|
+
}
|
|
390
|
+
return f.guidance ? `${f.message} ${f.guidance}` : f.message;
|
|
391
|
+
}
|
|
392
|
+
var MAX_RETRY_AFTER_MS = 15 * 60 * 1e3;
|
|
393
|
+
function parseRetryAfterMs(response) {
|
|
394
|
+
const raw = response.headers?.get?.("retry-after");
|
|
395
|
+
if (!raw) return void 0;
|
|
396
|
+
const trimmed = raw.trim();
|
|
397
|
+
let ms;
|
|
398
|
+
if (/^\d+(\.\d+)?$/.test(trimmed)) {
|
|
399
|
+
ms = Number(trimmed) * 1e3;
|
|
400
|
+
} else {
|
|
401
|
+
const at = Date.parse(trimmed);
|
|
402
|
+
if (Number.isNaN(at)) return void 0;
|
|
403
|
+
ms = at - Date.now();
|
|
404
|
+
}
|
|
405
|
+
return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, Math.round(ms)));
|
|
406
|
+
}
|
|
339
407
|
async function callVerifyAccessAPI(config, request) {
|
|
340
408
|
const { credentials, ...requestData } = request;
|
|
341
409
|
const body = {
|
|
@@ -392,7 +460,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
392
460
|
body: JSON.stringify(body),
|
|
393
461
|
signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
|
|
394
462
|
});
|
|
395
|
-
const data = await response
|
|
463
|
+
const data = await readJsonSafe(response);
|
|
464
|
+
const retryAfterMs = parseRetryAfterMs(response);
|
|
396
465
|
if (response.status === 410) {
|
|
397
466
|
return {
|
|
398
467
|
success: true,
|
|
@@ -430,6 +499,23 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
430
499
|
}
|
|
431
500
|
};
|
|
432
501
|
}
|
|
502
|
+
if (response.status === 404 && credentials.astraId && (data?.error === "AGENT_NOT_FOUND" || typeof data?.message === "string" && /agent/i.test(data.message))) {
|
|
503
|
+
return {
|
|
504
|
+
success: true,
|
|
505
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
506
|
+
access: {
|
|
507
|
+
allowed: false,
|
|
508
|
+
reason: "unknown_agent",
|
|
509
|
+
failures: [
|
|
510
|
+
{
|
|
511
|
+
dimension: "identity.unknown_agent",
|
|
512
|
+
message: "The presented agent identifier is not registered with AstraSync.",
|
|
513
|
+
guidance: UNKNOWN_AGENT_GUIDANCE
|
|
514
|
+
}
|
|
515
|
+
]
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
}
|
|
433
519
|
if (!response.ok) {
|
|
434
520
|
if (response.status === 401) {
|
|
435
521
|
return {
|
|
@@ -444,9 +530,11 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
444
530
|
}
|
|
445
531
|
return {
|
|
446
532
|
success: false,
|
|
447
|
-
error: data.message || data.error || `API returned ${response.status}`,
|
|
533
|
+
error: typeof data?.message === "string" && data.message || typeof data?.error === "string" && data.error || `API returned ${response.status}`,
|
|
448
534
|
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
449
|
-
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
535
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
536
|
+
httpStatus: response.status,
|
|
537
|
+
...retryAfterMs !== void 0 && { retryAfterMs }
|
|
450
538
|
};
|
|
451
539
|
}
|
|
452
540
|
return data;
|
|
@@ -518,12 +606,14 @@ async function verify(config, request, options) {
|
|
|
518
606
|
correlationId: apiResponse.correlationId,
|
|
519
607
|
attemptId: apiResponse.attemptId,
|
|
520
608
|
remediation: apiResponse.remediation,
|
|
609
|
+
httpStatus: apiResponse.httpStatus,
|
|
610
|
+
retryAfterMs: apiResponse.retryAfterMs,
|
|
521
611
|
urls
|
|
522
612
|
});
|
|
523
613
|
}
|
|
524
614
|
if (!apiResponse.access?.allowed) {
|
|
525
615
|
const aggregatedFailures = apiResponse.access?.failures;
|
|
526
|
-
const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true;
|
|
616
|
+
const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
|
|
527
617
|
const result2 = {
|
|
528
618
|
identityVerified: idVerifiedFromBackend,
|
|
529
619
|
policyAllowed: false,
|
|
@@ -535,7 +625,10 @@ async function verify(config, request, options) {
|
|
|
535
625
|
requiresStepUp: apiResponse.access?.requiresStepUp,
|
|
536
626
|
requiresApproval: apiResponse.access?.requiresApproval,
|
|
537
627
|
guidance: {
|
|
538
|
-
|
|
628
|
+
// 5.12.0: a presented-but-rejected id (malformed / unknown) carries
|
|
629
|
+
// actionable registration guidance on its failure — surface it
|
|
630
|
+
// instead of the bare machine reason ('unknown_agent').
|
|
631
|
+
message: rejectedIdentityGuidance(aggregatedFailures) ?? (apiResponse.access?.reason || "Access denied by PDLSS policy"),
|
|
539
632
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
540
633
|
documentationUrl: urls?.documentationUrl ?? "",
|
|
541
634
|
// 5.1.0: anonymous callers land on this branch — steer MCP-hosted
|
|
@@ -635,7 +728,7 @@ async function verify(config, request, options) {
|
|
|
635
728
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
636
729
|
documentationUrl: urls?.documentationUrl ?? ""
|
|
637
730
|
};
|
|
638
|
-
} else if (result.recommendation === "step_up_required") {
|
|
731
|
+
} else if (result.recommendation === "step_up_required" && result.identityVerified) {
|
|
639
732
|
result.requiresStepUp = true;
|
|
640
733
|
result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
|
|
641
734
|
}
|
|
@@ -1109,8 +1202,37 @@ function dedupeFailures(result) {
|
|
|
1109
1202
|
result.denialReasons = [...new Set(result.denialReasons)];
|
|
1110
1203
|
}
|
|
1111
1204
|
}
|
|
1205
|
+
function isReadOnlyMcpMethod(parsed) {
|
|
1206
|
+
return parsed.method !== "tools/call";
|
|
1207
|
+
}
|
|
1112
1208
|
function defaultMcpDenied(result, req, res) {
|
|
1113
1209
|
const id = req.body?.id ?? null;
|
|
1210
|
+
if (isVerificationUnavailable(result)) {
|
|
1211
|
+
const retryAfterSeconds = unavailableRetryAfterSeconds(result);
|
|
1212
|
+
const body = buildVerificationUnavailableBody(result).error;
|
|
1213
|
+
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
1214
|
+
res.setHeader(VERIFICATION_STATUS_HEADER, "unavailable");
|
|
1215
|
+
res.setHeader("Retry-After", String(retryAfterSeconds));
|
|
1216
|
+
res.status(503).json({
|
|
1217
|
+
jsonrpc: "2.0",
|
|
1218
|
+
id,
|
|
1219
|
+
error: {
|
|
1220
|
+
// -32003 → verification temporarily unavailable (retryable)
|
|
1221
|
+
code: -32003,
|
|
1222
|
+
message: body.message,
|
|
1223
|
+
data: {
|
|
1224
|
+
code: body.code,
|
|
1225
|
+
recommendation: "error",
|
|
1226
|
+
retryable: true,
|
|
1227
|
+
retryAfterSeconds,
|
|
1228
|
+
guidance: body.guidance,
|
|
1229
|
+
failures: result.failures,
|
|
1230
|
+
correlationId: result.correlationId
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
});
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1114
1236
|
if (result.misconfigured) {
|
|
1115
1237
|
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
1116
1238
|
res.status(503).json({
|
|
@@ -1129,7 +1251,7 @@ function defaultMcpDenied(result, req, res) {
|
|
|
1129
1251
|
});
|
|
1130
1252
|
return;
|
|
1131
1253
|
}
|
|
1132
|
-
const status
|
|
1254
|
+
const { status, code: denyCode } = denyStatusFor(result, "INSUFFICIENT_ACCESS");
|
|
1133
1255
|
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
1134
1256
|
res.status(status).json({
|
|
1135
1257
|
jsonrpc: "2.0",
|
|
@@ -1139,9 +1261,11 @@ function defaultMcpDenied(result, req, res) {
|
|
|
1139
1261
|
// -32000 → unauthorized (no identity resolved)
|
|
1140
1262
|
// -32001 → insufficient access (identity OK, policy denied)
|
|
1141
1263
|
// -32002 → merchant verification misconfigured (handled above)
|
|
1264
|
+
// -32003 → verification temporarily unavailable (handled above)
|
|
1142
1265
|
code: !result.identityVerified ? -32e3 : -32001,
|
|
1143
1266
|
message: result.denialReasons?.[0] ?? "Access denied",
|
|
1144
1267
|
data: {
|
|
1268
|
+
code: denyCode,
|
|
1145
1269
|
guidance: result.guidance,
|
|
1146
1270
|
// Round-10: aggregated per-dimension detail + correlation handle.
|
|
1147
1271
|
failures: result.failures,
|
|
@@ -1269,6 +1393,9 @@ function createMcpMiddleware(options) {
|
|
|
1269
1393
|
resolved_action: pdlss.action
|
|
1270
1394
|
});
|
|
1271
1395
|
}
|
|
1396
|
+
if (!pdlss.purpose && !shouldEnforce) {
|
|
1397
|
+
return next();
|
|
1398
|
+
}
|
|
1272
1399
|
if (!pdlss.purpose) {
|
|
1273
1400
|
const id = req.body?.id ?? null;
|
|
1274
1401
|
res.status(400).json({
|
|
@@ -1288,6 +1415,9 @@ function createMcpMiddleware(options) {
|
|
|
1288
1415
|
}
|
|
1289
1416
|
const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get("host")}${req.path}`;
|
|
1290
1417
|
const shouldRecordDecisions = recordDecisions !== false;
|
|
1418
|
+
const forwardedFor = req.headers["x-forwarded-for"];
|
|
1419
|
+
const forwardedForStr = Array.isArray(forwardedFor) ? forwardedFor.join(", ") : forwardedFor;
|
|
1420
|
+
const sourceIp = req.ip ?? (forwardedForStr ? forwardedForStr.split(",")[0].trim() : void 0);
|
|
1291
1421
|
const verificationRequest = {
|
|
1292
1422
|
credentials,
|
|
1293
1423
|
purpose: pdlss.purpose,
|
|
@@ -1302,9 +1432,10 @@ function createMcpMiddleware(options) {
|
|
|
1302
1432
|
counterpartyType: config.counterpartyType || "mcp_server",
|
|
1303
1433
|
enableRuntimeChallenge,
|
|
1304
1434
|
callerMetadata: {
|
|
1305
|
-
sourceIp
|
|
1435
|
+
sourceIp,
|
|
1306
1436
|
userAgent: req.headers["user-agent"],
|
|
1307
1437
|
host: req.headers.host,
|
|
1438
|
+
...forwardedForStr && { forwardedFor: forwardedForStr },
|
|
1308
1439
|
// Capture EVERY inbound header (parity with the express adapter —
|
|
1309
1440
|
// MCP-only merchants have no edge to do it upstream) plus the
|
|
1310
1441
|
// CDN-derived connection block. Local string work, secrets
|
|
@@ -1327,6 +1458,21 @@ function createMcpMiddleware(options) {
|
|
|
1327
1458
|
result.stepUpOutcome = outcome;
|
|
1328
1459
|
}
|
|
1329
1460
|
}
|
|
1461
|
+
if (!result.policyAllowed && isVerificationUnavailable(result) && (!shouldEnforce || isReadOnlyMcpMethod(parsed) && !credentials.astraId && !credentials.jwt)) {
|
|
1462
|
+
res.setHeader(VERIFICATION_STATUS_HEADER, "unavailable");
|
|
1463
|
+
return next();
|
|
1464
|
+
}
|
|
1465
|
+
if (!shouldEnforce) {
|
|
1466
|
+
if (config.setPassThroughHeader) {
|
|
1467
|
+
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
1468
|
+
res.setHeader("X-Astra-Gateway-Reason", "evaluated-not-enforced");
|
|
1469
|
+
}
|
|
1470
|
+
if (shouldRecordDecisions && sessionId) {
|
|
1471
|
+
recordDecision(config, sessionId, "granted").catch(() => {
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
return next();
|
|
1475
|
+
}
|
|
1330
1476
|
if (!result.policyAllowed) {
|
|
1331
1477
|
if (shouldRecordDecisions && sessionId) {
|
|
1332
1478
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
@@ -1346,17 +1492,6 @@ function createMcpMiddleware(options) {
|
|
|
1346
1492
|
onDenied(result, req, res);
|
|
1347
1493
|
return;
|
|
1348
1494
|
}
|
|
1349
|
-
if (!shouldEnforce) {
|
|
1350
|
-
if (config.setPassThroughHeader) {
|
|
1351
|
-
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
1352
|
-
res.setHeader("X-Astra-Gateway-Reason", "evaluated-not-enforced");
|
|
1353
|
-
}
|
|
1354
|
-
if (shouldRecordDecisions && sessionId) {
|
|
1355
|
-
recordDecision(config, sessionId, "granted").catch(() => {
|
|
1356
|
-
});
|
|
1357
|
-
}
|
|
1358
|
-
return next();
|
|
1359
|
-
}
|
|
1360
1495
|
if (effectiveAstraId) {
|
|
1361
1496
|
res.setHeader(
|
|
1362
1497
|
MCP_VERIFIED_HOP_HEADER,
|
|
@@ -1397,14 +1532,6 @@ function createMcpMiddleware(options) {
|
|
|
1397
1532
|
verifiedAt: /* @__PURE__ */ new Date(),
|
|
1398
1533
|
correlationId
|
|
1399
1534
|
};
|
|
1400
|
-
const catchUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
|
|
1401
|
-
if (catchUrls) {
|
|
1402
|
-
result.guidance = {
|
|
1403
|
-
message: `Middleware threw ${errorClass} \u2014 failing closed`,
|
|
1404
|
-
registrationUrl: catchUrls.registrationUrl,
|
|
1405
|
-
documentationUrl: catchUrls.documentationUrl
|
|
1406
|
-
};
|
|
1407
|
-
}
|
|
1408
1535
|
dedupeFailures(result);
|
|
1409
1536
|
return onDenied(result, req, res);
|
|
1410
1537
|
}
|