@astrasyncai/verification-gateway 3.0.0 → 3.2.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/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 +145 -93
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +145 -93
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +29 -11
- package/dist/adapters/mcp.d.ts +29 -11
- package/dist/adapters/mcp.js +43 -102
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +43 -102
- 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 +126 -56
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +126 -56
- 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/agent/index.js +3 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +3 -0
- package/dist/agent/index.mjs.map +1 -1
- 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-CrfwoNAR.d.ts → express-BowlMHQF.d.ts} +1 -1
- package/dist/{express-ienhAXps.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-CEg_WG6y.d.mts → index-B51W8gn8.d.mts} +1 -1
- package/dist/{index-DC5f8eoQ.d.ts → index-DBmlycVm.d.ts} +1 -1
- package/dist/{index-B5e2IDWU.d.mts → index-DtGziFEm.d.mts} +1 -1
- package/dist/{index-CCdZxvAr.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 +209 -191
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +209 -191
- 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-DSpisQst.d.mts → nextjs-BW1rzr1I.d.mts} +1 -1
- package/dist/{nextjs-66R1KW8e.d.ts → nextjs-V_K0qlAQ.d.ts} +1 -1
- package/dist/{sdk-5U_CBRpr.d.mts → sdk-ZYgI7G9f.d.ts} +14 -3
- package/dist/{sdk-Bm8np66n.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/transport/index.js +10 -0
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +10 -0
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-CgDCUfo8.d.mts → types-BNiLZY0i.d.mts} +1 -1
- package/dist/{types-R5N4ET6x.d.ts → types-DJi-u3fz.d.ts} +1 -1
- package/dist/{types-B3USs-Kx.d.mts → types-rFh4VMH4.d.mts} +30 -2
- package/dist/{types-B3USs-Kx.d.ts → types-rFh4VMH4.d.ts} +30 -2
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/adapters/mcp.mjs
CHANGED
|
@@ -1,24 +1,13 @@
|
|
|
1
1
|
// src/access-levels.ts
|
|
2
|
-
var ACCESS_LEVEL_HIERARCHY = {
|
|
3
|
-
none: 0,
|
|
4
|
-
restricted: 1,
|
|
5
|
-
"read-only": 2,
|
|
6
|
-
standard: 3,
|
|
7
|
-
full: 4,
|
|
8
|
-
internal: 5
|
|
9
|
-
};
|
|
10
2
|
function getTrustLevel(score) {
|
|
11
3
|
if (score >= 80) return "PLATINUM";
|
|
12
4
|
if (score >= 60) return "GOLD";
|
|
13
5
|
if (score >= 40) return "SILVER";
|
|
14
6
|
return "BRONZE";
|
|
15
7
|
}
|
|
16
|
-
function hasMinimumAccess(actual, required) {
|
|
17
|
-
return ACCESS_LEVEL_HIERARCHY[actual] >= ACCESS_LEVEL_HIERARCHY[required];
|
|
18
|
-
}
|
|
19
8
|
|
|
20
9
|
// src/version.ts
|
|
21
|
-
var SDK_VERSION = "3.
|
|
10
|
+
var SDK_VERSION = "3.2.0";
|
|
22
11
|
|
|
23
12
|
// src/well-known.ts
|
|
24
13
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -123,7 +112,7 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
|
123
112
|
}
|
|
124
113
|
}
|
|
125
114
|
var verificationCache = /* @__PURE__ */ new Map();
|
|
126
|
-
function getCacheKey(request) {
|
|
115
|
+
function getCacheKey(request, counterpartyId) {
|
|
127
116
|
const c = request.credentials;
|
|
128
117
|
return [
|
|
129
118
|
c.astraId || "",
|
|
@@ -136,6 +125,14 @@ function getCacheKey(request) {
|
|
|
136
125
|
request.jurisdiction || "",
|
|
137
126
|
request.transactionValue ?? "",
|
|
138
127
|
request.currency || "",
|
|
128
|
+
// SECURITY (cross-merchant cache leak): the merchant identity is sent via
|
|
129
|
+
// `config.counterpartyId`, NOT on the request, so it was previously absent
|
|
130
|
+
// from the key — two verifies for the SAME agent/purpose/action/value but
|
|
131
|
+
// DIFFERENT merchants collided, and a grant at a permissive merchant (low
|
|
132
|
+
// trust floor) was served for a stricter one. Same bug class as the
|
|
133
|
+
// duration omission (F-A1-07). counterpartyId affects the backend verdict
|
|
134
|
+
// (trust floor / per-route policy), so it MUST key the cache.
|
|
135
|
+
counterpartyId || "",
|
|
139
136
|
request.counterpartyUrl || "",
|
|
140
137
|
request.counterpartyType || "",
|
|
141
138
|
request.isSubAgentRequest ? "1" : "0",
|
|
@@ -159,8 +156,8 @@ function getCacheKey(request) {
|
|
|
159
156
|
request.callerMetadata?.agentCardUrl || ""
|
|
160
157
|
].join("|");
|
|
161
158
|
}
|
|
162
|
-
function getCachedResult(request) {
|
|
163
|
-
const key = getCacheKey(request);
|
|
159
|
+
function getCachedResult(request, counterpartyId) {
|
|
160
|
+
const key = getCacheKey(request, counterpartyId);
|
|
164
161
|
const cached = verificationCache.get(key);
|
|
165
162
|
if (cached && cached.expiresAt > Date.now()) {
|
|
166
163
|
return cached.result;
|
|
@@ -172,9 +169,9 @@ function getCachedResult(request) {
|
|
|
172
169
|
}
|
|
173
170
|
var DEFAULT_AUTONOMOUS_TTL_SECONDS = 60;
|
|
174
171
|
var DEFAULT_STEP_UP_TTL_SECONDS = 300;
|
|
175
|
-
function cacheResult(request, result, configuredTtl) {
|
|
172
|
+
function cacheResult(request, result, configuredTtl, counterpartyId) {
|
|
176
173
|
const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : result.requiresStepUp ? DEFAULT_STEP_UP_TTL_SECONDS : DEFAULT_AUTONOMOUS_TTL_SECONDS;
|
|
177
|
-
const key = getCacheKey(request);
|
|
174
|
+
const key = getCacheKey(request, counterpartyId);
|
|
178
175
|
verificationCache.set(key, {
|
|
179
176
|
result,
|
|
180
177
|
expiresAt: Date.now() + ttlSeconds * 1e3
|
|
@@ -366,7 +363,7 @@ async function verify(config, request) {
|
|
|
366
363
|
);
|
|
367
364
|
}
|
|
368
365
|
if (mergedConfig.cacheTtl !== 0) {
|
|
369
|
-
const cached = getCachedResult(request);
|
|
366
|
+
const cached = getCachedResult(request, mergedConfig.counterpartyId);
|
|
370
367
|
if (cached) {
|
|
371
368
|
if (mergedConfig.debug) {
|
|
372
369
|
console.log("[VerificationGateway] Returning cached result");
|
|
@@ -418,8 +415,8 @@ async function verify(config, request) {
|
|
|
418
415
|
verifiedAt: /* @__PURE__ */ new Date(),
|
|
419
416
|
// Extract sessionId so decisions can be recorded for denials too
|
|
420
417
|
sessionId: apiResponse.sessionId,
|
|
421
|
-
//
|
|
422
|
-
//
|
|
418
|
+
// Anonymous traffic has no session → correlationId is the per-attempt
|
|
419
|
+
// linking key (the sessionId-equivalent for anonymous callers).
|
|
423
420
|
correlationId: apiResponse.correlationId,
|
|
424
421
|
recommendation: apiResponse.recommendation,
|
|
425
422
|
recommendationReasons: apiResponse.recommendationReasons
|
|
@@ -493,17 +490,14 @@ async function verify(config, request) {
|
|
|
493
490
|
};
|
|
494
491
|
} else if (result.recommendation === "step_up_required") {
|
|
495
492
|
result.requiresStepUp = true;
|
|
496
|
-
if (ACCESS_LEVEL_HIERARCHY[result.accessLevel] > ACCESS_LEVEL_HIERARCHY["read-only"]) {
|
|
497
|
-
result.accessLevel = "read-only";
|
|
498
|
-
}
|
|
499
493
|
result.denialReasons = result.recommendationReasons || ["Step-up verification required"];
|
|
500
494
|
}
|
|
501
495
|
if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny") {
|
|
502
|
-
cacheResult(request, result, mergedConfig.cacheTtl);
|
|
496
|
+
cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
|
|
503
497
|
}
|
|
504
498
|
return result;
|
|
505
499
|
}
|
|
506
|
-
async function recordDecision(config, sessionId, decision, reason
|
|
500
|
+
async function recordDecision(config, sessionId, decision, reason) {
|
|
507
501
|
const headers = { "Content-Type": "application/json" };
|
|
508
502
|
if (config.apiKey) {
|
|
509
503
|
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
@@ -512,36 +506,7 @@ async function recordDecision(config, sessionId, decision, reason, override) {
|
|
|
512
506
|
await fetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
|
|
513
507
|
method: "POST",
|
|
514
508
|
headers,
|
|
515
|
-
body: JSON.stringify({
|
|
516
|
-
decision,
|
|
517
|
-
reason,
|
|
518
|
-
...override && {
|
|
519
|
-
overriddenBy: override.overriddenBy,
|
|
520
|
-
toolName: override.toolName,
|
|
521
|
-
requestedLevel: override.requestedLevel,
|
|
522
|
-
grantedLevel: override.grantedLevel
|
|
523
|
-
}
|
|
524
|
-
})
|
|
525
|
-
}).catch(() => {
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
async function recordAnonymousLocalOverride(config, correlationId, override, reason) {
|
|
529
|
-
const headers = { "Content-Type": "application/json" };
|
|
530
|
-
if (config.apiKey) {
|
|
531
|
-
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
532
|
-
headers["X-API-Key"] = config.apiKey;
|
|
533
|
-
}
|
|
534
|
-
await fetch(`${config.apiBaseUrl}/agents/verify-access/local-override`, {
|
|
535
|
-
method: "POST",
|
|
536
|
-
headers,
|
|
537
|
-
body: JSON.stringify({
|
|
538
|
-
correlationId,
|
|
539
|
-
reason,
|
|
540
|
-
overriddenBy: override.overriddenBy,
|
|
541
|
-
toolName: override.toolName,
|
|
542
|
-
requestedLevel: override.requestedLevel,
|
|
543
|
-
grantedLevel: override.grantedLevel
|
|
544
|
-
})
|
|
509
|
+
body: JSON.stringify({ decision, reason })
|
|
545
510
|
}).catch(() => {
|
|
546
511
|
});
|
|
547
512
|
}
|
|
@@ -644,7 +609,10 @@ function mcpToPdlss(parsed, requestPath, headerPurpose, headerAction, toolGate)
|
|
|
644
609
|
}
|
|
645
610
|
let action;
|
|
646
611
|
let actionSource;
|
|
647
|
-
if (
|
|
612
|
+
if (toolGate?.action !== void 0) {
|
|
613
|
+
action = toolGate.action;
|
|
614
|
+
actionSource = "tool_gate";
|
|
615
|
+
} else if (headerAction) {
|
|
648
616
|
action = headerAction;
|
|
649
617
|
actionSource = "header";
|
|
650
618
|
} else if (parsed.actionFromBody && parsed.actionSourceFromBody) {
|
|
@@ -755,7 +723,6 @@ function createMcpMiddleware(options) {
|
|
|
755
723
|
return next();
|
|
756
724
|
}
|
|
757
725
|
req.mcpRequest = parsed;
|
|
758
|
-
const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
|
|
759
726
|
const headerRaw = req.headers["x-astra-id"] ?? req.headers["x-astra-agentid"];
|
|
760
727
|
const headerAstraId = typeof headerRaw === "string" ? headerRaw : Array.isArray(headerRaw) ? headerRaw[0] : void 0;
|
|
761
728
|
const bodyAstraId = parsed.agentIdFromBody;
|
|
@@ -792,7 +759,7 @@ function createMcpMiddleware(options) {
|
|
|
792
759
|
return next();
|
|
793
760
|
}
|
|
794
761
|
}
|
|
795
|
-
const { level: minAccessLevel
|
|
762
|
+
const { level: minAccessLevel } = resolveMinAccessLevel(parsed, {
|
|
796
763
|
toolGates,
|
|
797
764
|
methodGates
|
|
798
765
|
});
|
|
@@ -818,7 +785,7 @@ function createMcpMiddleware(options) {
|
|
|
818
785
|
req.path,
|
|
819
786
|
headerPurpose,
|
|
820
787
|
headerAction,
|
|
821
|
-
gate ? { purpose: gate.purpose, resource: gate.resource } : void 0
|
|
788
|
+
gate ? { purpose: gate.purpose, action: gate.action, resource: gate.resource } : void 0
|
|
822
789
|
);
|
|
823
790
|
if (config.debug) {
|
|
824
791
|
console.debug("[mcp-middleware] pdlss resolved", {
|
|
@@ -828,6 +795,23 @@ function createMcpMiddleware(options) {
|
|
|
828
795
|
resolved_action: pdlss.action
|
|
829
796
|
});
|
|
830
797
|
}
|
|
798
|
+
if (!pdlss.purpose) {
|
|
799
|
+
const id = req.body?.id ?? null;
|
|
800
|
+
res.status(400).json({
|
|
801
|
+
jsonrpc: "2.0",
|
|
802
|
+
id,
|
|
803
|
+
error: {
|
|
804
|
+
code: -32602,
|
|
805
|
+
message: "PDLSS_PURPOSE_REQUIRED",
|
|
806
|
+
data: {
|
|
807
|
+
dimension: "pdlss.purpose",
|
|
808
|
+
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.",
|
|
809
|
+
resolvedAction: pdlss.action
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
831
815
|
const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get("host")}${req.path}`;
|
|
832
816
|
const shouldRecordDecisions = recordDecisions !== false;
|
|
833
817
|
const result = await verify(config, {
|
|
@@ -851,7 +835,6 @@ function createMcpMiddleware(options) {
|
|
|
851
835
|
});
|
|
852
836
|
req.agentVerification = result;
|
|
853
837
|
const sessionId = result.sessionId;
|
|
854
|
-
const correlationId = result.correlationId;
|
|
855
838
|
if (!result.identityVerified || !result.policyAllowed) {
|
|
856
839
|
if (shouldRecordDecisions && sessionId) {
|
|
857
840
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
@@ -872,48 +855,6 @@ function createMcpMiddleware(options) {
|
|
|
872
855
|
}
|
|
873
856
|
return next();
|
|
874
857
|
}
|
|
875
|
-
if (!hasMinimumAccess(result.accessLevel, minAccessLevel)) {
|
|
876
|
-
const insufficientFailure = {
|
|
877
|
-
dimension: "access_level.insufficient",
|
|
878
|
-
message: `Tool requires accessLevel '${minAccessLevel}'; agent has '${result.accessLevel}'.`,
|
|
879
|
-
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."
|
|
880
|
-
};
|
|
881
|
-
result.failures = [...result.failures ?? [], insufficientFailure];
|
|
882
|
-
result.denialReasons = [...result.denialReasons ?? [], insufficientFailure.message];
|
|
883
|
-
if (!result.guidance && wellKnownUrls) {
|
|
884
|
-
result.guidance = {
|
|
885
|
-
message: insufficientFailure.message,
|
|
886
|
-
registrationUrl: wellKnownUrls.registrationUrl,
|
|
887
|
-
documentationUrl: wellKnownUrls.documentationUrl
|
|
888
|
-
};
|
|
889
|
-
}
|
|
890
|
-
if (shouldRecordDecisions) {
|
|
891
|
-
const overrideKind = gateSource === "toolGate" ? "toolGate" : gateSource === "methodGate" ? "methodGate" : "other";
|
|
892
|
-
const override = {
|
|
893
|
-
overriddenBy: overrideKind,
|
|
894
|
-
...parsed.toolName && { toolName: parsed.toolName },
|
|
895
|
-
requestedLevel: minAccessLevel,
|
|
896
|
-
grantedLevel: result.accessLevel
|
|
897
|
-
};
|
|
898
|
-
if (sessionId) {
|
|
899
|
-
recordDecision(config, sessionId, "denied", result.denialReasons?.[0], override).catch(
|
|
900
|
-
() => {
|
|
901
|
-
}
|
|
902
|
-
);
|
|
903
|
-
} else if (correlationId) {
|
|
904
|
-
recordAnonymousLocalOverride(
|
|
905
|
-
config,
|
|
906
|
-
correlationId,
|
|
907
|
-
override,
|
|
908
|
-
result.denialReasons?.[0]
|
|
909
|
-
).catch(() => {
|
|
910
|
-
});
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
dedupeFailures(result);
|
|
914
|
-
onDenied(result, req, res);
|
|
915
|
-
return;
|
|
916
|
-
}
|
|
917
858
|
if (effectiveAstraId) {
|
|
918
859
|
res.setHeader(
|
|
919
860
|
MCP_VERIFIED_HOP_HEADER,
|