@astrasyncai/verification-gateway 5.18.1 → 5.19.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/CHANGELOG.md +149 -0
- package/README.md +168 -4
- package/dist/adapters/express.d.mts +9 -1
- package/dist/adapters/express.d.ts +9 -1
- package/dist/adapters/express.js +96 -37
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +96 -37
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/http-pdlss.d.mts +7 -1
- package/dist/adapters/http-pdlss.d.ts +7 -1
- package/dist/adapters/http-pdlss.js +18 -2
- package/dist/adapters/http-pdlss.js.map +1 -1
- package/dist/adapters/http-pdlss.mjs +16 -1
- package/dist/adapters/http-pdlss.mjs.map +1 -1
- package/dist/adapters/kit-express.d.mts +93 -1
- package/dist/adapters/kit-express.d.ts +93 -1
- package/dist/adapters/kit-express.js +181 -2
- package/dist/adapters/kit-express.js.map +1 -1
- package/dist/adapters/kit-express.mjs +180 -2
- package/dist/adapters/kit-express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +80 -9
- package/dist/adapters/mcp.d.ts +80 -9
- package/dist/adapters/mcp.js +153 -5
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +151 -5
- 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 +41 -4
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +41 -4
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +44 -1
- package/dist/adapters/sdk.d.ts +44 -1
- package/dist/adapters/sdk.js +76 -2
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +76 -2
- 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 +46 -6
- package/dist/bin/astrasync-codex-hook.js +46 -6
- package/dist/bin/astrasync-guard.js +46 -6
- package/dist/bin/astrasync.js +77 -5
- package/dist/browser/background.js +46 -6
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +46 -6
- 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 +46 -6
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +46 -6
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +46 -6
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +46 -6
- 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 +1 -1
- package/dist/edge-core/index.d.ts +1 -1
- package/dist/edge-core/index.js +21 -2
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +21 -2
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +46 -6
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +46 -6
- 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 +541 -29
- package/dist/index.d.ts +541 -29
- package/dist/index.js +1171 -183
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1157 -173
- package/dist/index.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 +3 -2
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +3 -2
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-3ObBpsnf.d.mts → types-BoGjyon0.d.mts} +81 -2
- package/dist/{types-Cns4l8gX.d.mts → types-DqWPkiYl.d.mts} +90 -12
- package/dist/{types-Cns4l8gX.d.ts → types-DqWPkiYl.d.ts} +90 -12
- package/dist/{types-BoxZEYPS.d.ts → types-eWyZuz-3.d.ts} +81 -2
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +23 -2
- package/dist/verify.d.ts +23 -2
- package/dist/verify.js +23 -4
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +23 -4
- package/dist/verify.mjs.map +1 -1
- package/dist/webhooks.d.mts +16 -3
- package/dist/webhooks.d.ts +16 -3
- package/dist/webhooks.js +24 -13
- package/dist/webhooks.js.map +1 -1
- package/dist/webhooks.mjs +24 -13
- package/dist/webhooks.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.19.0";
|
|
3
3
|
|
|
4
4
|
// src/http.ts
|
|
5
5
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -241,7 +241,12 @@ function getCacheKey(request, counterpartyId) {
|
|
|
241
241
|
// its start_checkout quote was served the cached quote-leg grant (no
|
|
242
242
|
// settlementOutcome) and never reached the backend. Same F-A1-07 bug class.
|
|
243
243
|
request.commercePhase || "",
|
|
244
|
-
request.checkoutSessionId || ""
|
|
244
|
+
request.checkoutSessionId || "",
|
|
245
|
+
// 5.19.0: a route_config purpose claim is checked server-side against
|
|
246
|
+
// the stored rule for this method + path, so it changes the verdict.
|
|
247
|
+
request.purposeSource || "",
|
|
248
|
+
request.requestMethod || "",
|
|
249
|
+
request.requestPath || ""
|
|
245
250
|
].join("|");
|
|
246
251
|
}
|
|
247
252
|
function getCachedResult(request, counterpartyId) {
|
|
@@ -449,6 +454,11 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
449
454
|
if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
|
|
450
455
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
451
456
|
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
457
|
+
if (requestData.purposeSource) body.purposeSource = requestData.purposeSource;
|
|
458
|
+
if (requestData.agentArtifacts) body.agentArtifacts = requestData.agentArtifacts;
|
|
459
|
+
if (requestData.metadata) body.metadata = requestData.metadata;
|
|
460
|
+
if (requestData.requestMethod) body.requestMethod = requestData.requestMethod;
|
|
461
|
+
if (requestData.requestPath) body.requestPath = requestData.requestPath;
|
|
452
462
|
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
453
463
|
body.sdkVersion = SDK_VERSION;
|
|
454
464
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
@@ -638,9 +648,18 @@ async function verify(config, request, options) {
|
|
|
638
648
|
if (!apiResponse.access?.allowed) {
|
|
639
649
|
const aggregatedFailures = apiResponse.access?.failures;
|
|
640
650
|
const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
|
|
651
|
+
const denyAgent = idVerifiedFromBackend && apiResponse.agent ? {
|
|
652
|
+
astraId: apiResponse.agent.astraId,
|
|
653
|
+
name: apiResponse.agent.name,
|
|
654
|
+
trustScore: apiResponse.agent.trustScore,
|
|
655
|
+
trustLevel: getTrustLevel(apiResponse.agent.trustScore),
|
|
656
|
+
blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
|
|
657
|
+
status: apiResponse.agent.agentStatus
|
|
658
|
+
} : void 0;
|
|
641
659
|
const result2 = {
|
|
642
660
|
identityVerified: idVerifiedFromBackend,
|
|
643
661
|
policyAllowed: false,
|
|
662
|
+
...denyAgent && { agent: denyAgent },
|
|
644
663
|
// 3.6.0: the server now emits top-level denialReasons on every deny
|
|
645
664
|
// path — prefer it verbatim; the failure-message reconstruction remains
|
|
646
665
|
// as the fallback for older backends.
|
|
@@ -789,6 +808,34 @@ async function recordDecision(config, sessionId, decision, reason) {
|
|
|
789
808
|
}).catch(() => {
|
|
790
809
|
});
|
|
791
810
|
}
|
|
811
|
+
var refusedPolicyReads = /* @__PURE__ */ new Set();
|
|
812
|
+
async function fetchRoutes(config, counterpartyId, options = {}) {
|
|
813
|
+
if (!counterpartyId) return null;
|
|
814
|
+
const headers = { "Content-Type": "application/json" };
|
|
815
|
+
if (config.apiKey) {
|
|
816
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
817
|
+
headers["X-API-Key"] = config.apiKey;
|
|
818
|
+
}
|
|
819
|
+
try {
|
|
820
|
+
const response = await sdkFetch(
|
|
821
|
+
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes` + (options.codeGates?.length ? `?codeGates=${options.codeGates.map(encodeURIComponent).join(",")}` : ""),
|
|
822
|
+
{ method: "GET", headers }
|
|
823
|
+
);
|
|
824
|
+
if (!response.ok) {
|
|
825
|
+
if ((response.status === 401 || response.status === 403 || response.status === 404) && !refusedPolicyReads.has(counterpartyId)) {
|
|
826
|
+
refusedPolicyReads.add(counterpartyId);
|
|
827
|
+
console.error(
|
|
828
|
+
`[VerificationGateway] the configured API key cannot read the route policy for ${counterpartyId} (HTTP ${response.status}). The key belongs to an account that does not own this endpoint, or the counterpartyId is wrong. The gateway is in PASS-THROUGH mode: no agent is being verified.`
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
return null;
|
|
832
|
+
}
|
|
833
|
+
const body = await response.json();
|
|
834
|
+
return body.data?.routes ?? [];
|
|
835
|
+
} catch {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
792
839
|
|
|
793
840
|
// src/metadata-capture.ts
|
|
794
841
|
var CAPTURE_SCHEMA_VERSION = 1;
|
|
@@ -1111,6 +1158,42 @@ async function awaitStepUpApproval(config, approval) {
|
|
|
1111
1158
|
return "timeout";
|
|
1112
1159
|
}
|
|
1113
1160
|
|
|
1161
|
+
// src/adapters/routes-cache.ts
|
|
1162
|
+
var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
|
|
1163
|
+
function createRoutesCache(config, opts = {}) {
|
|
1164
|
+
const refreshMs = opts.refreshMs ?? DEFAULT_ROUTES_REFRESH_MS;
|
|
1165
|
+
let cached = [];
|
|
1166
|
+
let lastFetchAt = 0;
|
|
1167
|
+
let refreshing = null;
|
|
1168
|
+
async function refresh() {
|
|
1169
|
+
if (!config.counterpartyId) {
|
|
1170
|
+
opts.onNoCounterparty?.();
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
const fetched = await fetchRoutes(config, config.counterpartyId, opts.fetchOptions);
|
|
1174
|
+
if (fetched) {
|
|
1175
|
+
cached = fetched;
|
|
1176
|
+
lastFetchAt = Date.now();
|
|
1177
|
+
opts.onFetched?.(fetched);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
function start() {
|
|
1181
|
+
refreshing = refresh().catch(() => void 0).finally(() => {
|
|
1182
|
+
refreshing = null;
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
start();
|
|
1186
|
+
return {
|
|
1187
|
+
async current() {
|
|
1188
|
+
if (refreshing) await refreshing.catch(() => {
|
|
1189
|
+
});
|
|
1190
|
+
if (config.counterpartyId && Date.now() - lastFetchAt > refreshMs) start();
|
|
1191
|
+
return cached;
|
|
1192
|
+
},
|
|
1193
|
+
peek: () => cached
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1114
1197
|
// src/verified-hop.ts
|
|
1115
1198
|
var MCP_VERIFIED_HOP_HEADER = "X-Astra-Verified-Hop";
|
|
1116
1199
|
var MCP_VERIFIED_HOP_MAX_AGE_MS = 6e4;
|
|
@@ -1331,6 +1414,21 @@ function defaultMcpDenied(result, req, res) {
|
|
|
1331
1414
|
}
|
|
1332
1415
|
});
|
|
1333
1416
|
}
|
|
1417
|
+
function dashboardToolRules(routes) {
|
|
1418
|
+
const out = /* @__PURE__ */ new Map();
|
|
1419
|
+
for (const r of routes) {
|
|
1420
|
+
if (typeof r.tool !== "string" || !r.tool || r.legacy === true) continue;
|
|
1421
|
+
if (out.has(r.tool)) continue;
|
|
1422
|
+
out.set(r.tool, {
|
|
1423
|
+
tool: r.tool,
|
|
1424
|
+
...r.purpose && { purpose: r.purpose },
|
|
1425
|
+
...r.action && { action: r.action },
|
|
1426
|
+
...r.resource && { resource: r.resource },
|
|
1427
|
+
...r.observe === true && { observe: true }
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
return out;
|
|
1431
|
+
}
|
|
1334
1432
|
function resolveGate(parsed, opts) {
|
|
1335
1433
|
if (!parsed.toolName) {
|
|
1336
1434
|
const methodGate = opts.methodGates?.[parsed.method];
|
|
@@ -1340,8 +1438,30 @@ function resolveGate(parsed, opts) {
|
|
|
1340
1438
|
return { enforce: false, source: "discovery_default" };
|
|
1341
1439
|
}
|
|
1342
1440
|
const toolGate = opts.toolGates?.[parsed.toolName];
|
|
1441
|
+
const rule = opts.dashboardRules?.get(parsed.toolName);
|
|
1442
|
+
const fromRule = (r) => r.observe ? { enforce: false, source: "dashboard" } : {
|
|
1443
|
+
enforce: true,
|
|
1444
|
+
config: {
|
|
1445
|
+
...r.purpose && { purpose: r.purpose },
|
|
1446
|
+
...r.action && { action: r.action },
|
|
1447
|
+
...r.resource && { resource: r.resource }
|
|
1448
|
+
},
|
|
1449
|
+
source: "dashboard"
|
|
1450
|
+
};
|
|
1451
|
+
const codeGated = toolGate !== void 0 && toolGate !== "observe";
|
|
1452
|
+
if (rule && (opts.toolGatePrecedence === "dashboard" || !codeGated)) return fromRule(rule);
|
|
1343
1453
|
if (toolGate !== void 0) {
|
|
1344
|
-
|
|
1454
|
+
if (toolGate === "observe") return { enforce: false, source: "toolGate" };
|
|
1455
|
+
if (rule && !rule.observe && rule.purpose && (rule.purpose !== toolGate.purpose || rule.action && rule.action !== toolGate.action)) {
|
|
1456
|
+
const extra = fromRule(rule).config;
|
|
1457
|
+
return {
|
|
1458
|
+
enforce: true,
|
|
1459
|
+
config: toolGate,
|
|
1460
|
+
additional: { ...extra, ...!extra.resource && toolGate.resource && { resource: toolGate.resource } },
|
|
1461
|
+
source: "toolGate"
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
return { enforce: true, config: toolGate, source: "toolGate" };
|
|
1345
1465
|
}
|
|
1346
1466
|
return { enforce: mcpDefaultEnforced(parsed), source: "tier" };
|
|
1347
1467
|
}
|
|
@@ -1356,13 +1476,20 @@ function createMcpMiddleware(options) {
|
|
|
1356
1476
|
verifiedHopMaxAgeMs,
|
|
1357
1477
|
recordDecisions,
|
|
1358
1478
|
enableRuntimeChallenge = true,
|
|
1359
|
-
failOnError = "
|
|
1479
|
+
failOnError = "closed",
|
|
1480
|
+
toolGatePrecedence = "code",
|
|
1481
|
+
routesRefreshMs,
|
|
1360
1482
|
...config
|
|
1361
1483
|
} = options;
|
|
1362
1484
|
if (config.apiBaseUrl) {
|
|
1363
1485
|
prefetchWellKnown(config.apiBaseUrl).catch(() => {
|
|
1364
1486
|
});
|
|
1365
1487
|
}
|
|
1488
|
+
const codeGatedTools = Object.entries(toolGates ?? {}).filter(([, g]) => g !== "observe").map(([name]) => name);
|
|
1489
|
+
const rulesCache = config.apiKey && config.counterpartyId ? createRoutesCache(config, {
|
|
1490
|
+
...routesRefreshMs !== void 0 && { refreshMs: routesRefreshMs },
|
|
1491
|
+
...codeGatedTools.length && { fetchOptions: { codeGates: codeGatedTools } }
|
|
1492
|
+
}) : void 0;
|
|
1366
1493
|
return async (req, res, next) => {
|
|
1367
1494
|
try {
|
|
1368
1495
|
if (skip) return next();
|
|
@@ -1411,9 +1538,12 @@ function createMcpMiddleware(options) {
|
|
|
1411
1538
|
return next();
|
|
1412
1539
|
}
|
|
1413
1540
|
}
|
|
1541
|
+
const dashboardRules = rulesCache ? dashboardToolRules(await rulesCache.current()) : void 0;
|
|
1414
1542
|
const gateDecision = resolveGate(parsed, {
|
|
1415
1543
|
toolGates,
|
|
1416
|
-
methodGates
|
|
1544
|
+
methodGates,
|
|
1545
|
+
dashboardRules,
|
|
1546
|
+
toolGatePrecedence
|
|
1417
1547
|
});
|
|
1418
1548
|
const credentials = extractCredentials(
|
|
1419
1549
|
req.headers,
|
|
@@ -1511,6 +1641,20 @@ function createMcpMiddleware(options) {
|
|
|
1511
1641
|
result.stepUpOutcome = outcome;
|
|
1512
1642
|
}
|
|
1513
1643
|
}
|
|
1644
|
+
if (shouldEnforce && gateDecision.additional?.purpose && result.policyAllowed && !requiresHumanApproval(result)) {
|
|
1645
|
+
const extra = mcpToPdlss(parsed, req.path, void 0, void 0, gateDecision.additional);
|
|
1646
|
+
const extraResult = await verify(config, {
|
|
1647
|
+
...verificationRequest,
|
|
1648
|
+
purpose: extra.purpose,
|
|
1649
|
+
action: extra.action,
|
|
1650
|
+
resource: extra.resource
|
|
1651
|
+
});
|
|
1652
|
+
if (!extraResult.policyAllowed || requiresHumanApproval(extraResult)) {
|
|
1653
|
+
result = extraResult;
|
|
1654
|
+
req.agentVerification = result;
|
|
1655
|
+
sessionId = result.sessionId;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1514
1658
|
if (!result.policyAllowed && isVerificationUnavailable(result) && (!shouldEnforce || isReadOnlyMcpMethod(parsed) && !credentials.astraId && !credentials.jwt)) {
|
|
1515
1659
|
res.setHeader(VERIFICATION_STATUS_HEADER, "unavailable");
|
|
1516
1660
|
return next();
|
|
@@ -1595,11 +1739,13 @@ function createMcpMiddleware(options) {
|
|
|
1595
1739
|
export {
|
|
1596
1740
|
MCP_VERIFIED_HOP_HEADER,
|
|
1597
1741
|
createMcpMiddleware,
|
|
1742
|
+
dashboardToolRules,
|
|
1598
1743
|
isVerifiedHopValidFor,
|
|
1599
1744
|
mcpDefaultEnforced,
|
|
1600
1745
|
mcpToPdlss,
|
|
1601
1746
|
parseMcpJsonRpc,
|
|
1602
1747
|
parseVerifiedHop,
|
|
1748
|
+
resolveGate,
|
|
1603
1749
|
serializeVerifiedHop
|
|
1604
1750
|
};
|
|
1605
1751
|
//# sourceMappingURL=mcp.mjs.map
|