@astrasyncai/verification-gateway 5.18.1 → 5.20.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 +232 -0
- package/README.md +217 -4
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +9 -1
- package/dist/adapters/express.d.ts +9 -1
- package/dist/adapters/express.js +160 -52
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +160 -52
- 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 +102 -9
- package/dist/adapters/mcp.d.ts +102 -9
- package/dist/adapters/mcp.js +242 -19
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +240 -19
- 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 +97 -14
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +97 -14
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +101 -2
- package/dist/adapters/sdk.d.ts +101 -2
- package/dist/adapters/sdk.js +199 -12
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +199 -12
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +1 -1
- package/dist/agent/index.d.ts +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 +94 -16
- package/dist/bin/astrasync-codex-hook.js +94 -16
- package/dist/bin/astrasync-guard.js +94 -16
- package/dist/bin/astrasync.js +127 -16
- package/dist/browser/background.js +94 -16
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +94 -16
- 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 +94 -16
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +94 -16
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +94 -16
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +94 -16
- 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 +69 -12
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +69 -12
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +94 -16
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +94 -16
- 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 +706 -34
- package/dist/index.d.ts +706 -34
- package/dist/index.js +1391 -205
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1374 -195
- 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/registration/index.d.mts +11 -2
- package/dist/registration/index.d.ts +11 -2
- 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.d.mts +1 -1
- package/dist/transport/index.d.ts +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-BRz2U0Pn.d.ts → types-B_HLhZ9n.d.ts} +1 -1
- package/dist/{types-BfILnheI.d.mts → types-CU17R4Nr.d.mts} +11 -0
- package/dist/{types-BfILnheI.d.ts → types-CU17R4Nr.d.ts} +11 -0
- package/dist/{types-Cns4l8gX.d.mts → types-CxjqmPl-.d.mts} +115 -13
- package/dist/{types-Cns4l8gX.d.ts → types-CxjqmPl-.d.ts} +115 -13
- package/dist/{types-3ObBpsnf.d.mts → types-D37aSQ9c.d.mts} +106 -3
- package/dist/{types-CfBpm3w5.d.mts → types-Djpz-L0w.d.mts} +1 -1
- package/dist/{types-BoxZEYPS.d.ts → types-Dn8tXnei.d.ts} +106 -3
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +50 -4
- package/dist/verify.d.ts +50 -4
- package/dist/verify.js +93 -14
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +91 -14
- 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/express.js
CHANGED
|
@@ -479,7 +479,7 @@ function routePolicyOf(route) {
|
|
|
479
479
|
}
|
|
480
480
|
|
|
481
481
|
// src/version.ts
|
|
482
|
-
var SDK_VERSION = "5.
|
|
482
|
+
var SDK_VERSION = "5.20.0";
|
|
483
483
|
|
|
484
484
|
// src/http.ts
|
|
485
485
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -797,7 +797,12 @@ function getCacheKey(request, counterpartyId) {
|
|
|
797
797
|
// its start_checkout quote was served the cached quote-leg grant (no
|
|
798
798
|
// settlementOutcome) and never reached the backend. Same F-A1-07 bug class.
|
|
799
799
|
request.commercePhase || "",
|
|
800
|
-
request.checkoutSessionId || ""
|
|
800
|
+
request.checkoutSessionId || "",
|
|
801
|
+
// 5.19.0: a route_config purpose claim is checked server-side against
|
|
802
|
+
// the stored rule for this method + path, so it changes the verdict.
|
|
803
|
+
request.purposeSource || "",
|
|
804
|
+
request.requestMethod || "",
|
|
805
|
+
request.requestPath || ""
|
|
801
806
|
].join("|");
|
|
802
807
|
}
|
|
803
808
|
function getCachedResult(request, counterpartyId) {
|
|
@@ -989,6 +994,9 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
989
994
|
if (requestData.enableRuntimeChallenge)
|
|
990
995
|
body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
|
|
991
996
|
if (requestData.routePolicy) body.routePolicy = requestData.routePolicy;
|
|
997
|
+
if (config.actingProof?.connectorToken) {
|
|
998
|
+
body.actingProof = { connectorToken: config.actingProof.connectorToken };
|
|
999
|
+
}
|
|
992
1000
|
if (requestData.approvalHeldByRoute) body.approvalHeldByRoute = true;
|
|
993
1001
|
if (requestData.createSession) body.createSession = requestData.createSession;
|
|
994
1002
|
if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
|
|
@@ -1005,6 +1013,11 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
1005
1013
|
if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
|
|
1006
1014
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
1007
1015
|
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
1016
|
+
if (requestData.purposeSource) body.purposeSource = requestData.purposeSource;
|
|
1017
|
+
if (requestData.agentArtifacts) body.agentArtifacts = requestData.agentArtifacts;
|
|
1018
|
+
if (requestData.metadata) body.metadata = requestData.metadata;
|
|
1019
|
+
if (requestData.requestMethod) body.requestMethod = requestData.requestMethod;
|
|
1020
|
+
if (requestData.requestPath) body.requestPath = requestData.requestPath;
|
|
1008
1021
|
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
1009
1022
|
body.sdkVersion = SDK_VERSION;
|
|
1010
1023
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
@@ -1151,22 +1164,46 @@ async function verify(config, request, options) {
|
|
|
1151
1164
|
"[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access decisions (verified ID + runtime challenge + PDLSS + trust score). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
|
|
1152
1165
|
);
|
|
1153
1166
|
}
|
|
1154
|
-
const uncacheable = Boolean(request.commerceArtifacts);
|
|
1167
|
+
const uncacheable = Boolean(request.commerceArtifacts) || Boolean(mergedConfig.actingProof);
|
|
1155
1168
|
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
1156
1169
|
const cached = getCachedResult(request, mergedConfig.counterpartyId);
|
|
1157
1170
|
if (cached) {
|
|
1158
1171
|
if (mergedConfig.debug) {
|
|
1159
1172
|
console.log("[VerificationGateway] Returning cached result");
|
|
1160
1173
|
}
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1174
|
+
return sharedVerdict(cached, request);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
1178
|
+
const key = getCacheKey(request, mergedConfig.counterpartyId);
|
|
1179
|
+
const pending = inflightVerifies.get(key);
|
|
1180
|
+
if (pending) return sharedVerdict(await pending, request);
|
|
1181
|
+
const flight = verifyViaApi(mergedConfig, request, urls, uncacheable);
|
|
1182
|
+
inflightVerifies.set(key, flight);
|
|
1183
|
+
try {
|
|
1184
|
+
return await flight;
|
|
1185
|
+
} finally {
|
|
1186
|
+
inflightVerifies.delete(key);
|
|
1168
1187
|
}
|
|
1169
1188
|
}
|
|
1189
|
+
return verifyViaApi(mergedConfig, request, urls, uncacheable);
|
|
1190
|
+
}
|
|
1191
|
+
var inflightVerifies = /* @__PURE__ */ new Map();
|
|
1192
|
+
var sharedVerdicts = /* @__PURE__ */ new WeakSet();
|
|
1193
|
+
function isSharedVerdict(result) {
|
|
1194
|
+
return sharedVerdicts.has(result);
|
|
1195
|
+
}
|
|
1196
|
+
function sharedVerdict(source, request) {
|
|
1197
|
+
const hit = { ...source };
|
|
1198
|
+
if (request.attemptId) {
|
|
1199
|
+
hit.attemptId = request.attemptId;
|
|
1200
|
+
} else {
|
|
1201
|
+
delete hit.attemptId;
|
|
1202
|
+
}
|
|
1203
|
+
sharedVerdicts.add(hit);
|
|
1204
|
+
return hit;
|
|
1205
|
+
}
|
|
1206
|
+
async function verifyViaApi(mergedConfig, request, urls, uncacheable) {
|
|
1170
1207
|
const enrichedRequest = { ...request };
|
|
1171
1208
|
if (!enrichedRequest.counterpartyUrl && mergedConfig.counterpartyUrl) {
|
|
1172
1209
|
enrichedRequest.counterpartyUrl = mergedConfig.counterpartyUrl;
|
|
@@ -1194,9 +1231,18 @@ async function verify(config, request, options) {
|
|
|
1194
1231
|
if (!apiResponse.access?.allowed) {
|
|
1195
1232
|
const aggregatedFailures = apiResponse.access?.failures;
|
|
1196
1233
|
const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
|
|
1234
|
+
const denyAgent = idVerifiedFromBackend && apiResponse.agent ? {
|
|
1235
|
+
astraId: apiResponse.agent.astraId,
|
|
1236
|
+
name: apiResponse.agent.name,
|
|
1237
|
+
trustScore: apiResponse.agent.trustScore,
|
|
1238
|
+
trustLevel: getTrustLevel(apiResponse.agent.trustScore),
|
|
1239
|
+
blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
|
|
1240
|
+
status: apiResponse.agent.agentStatus
|
|
1241
|
+
} : void 0;
|
|
1197
1242
|
const result2 = {
|
|
1198
1243
|
identityVerified: idVerifiedFromBackend,
|
|
1199
1244
|
policyAllowed: false,
|
|
1245
|
+
...denyAgent && { agent: denyAgent },
|
|
1200
1246
|
// 3.6.0: the server now emits top-level denialReasons on every deny
|
|
1201
1247
|
// path — prefer it verbatim; the failure-message reconstruction remains
|
|
1202
1248
|
// as the fallback for older backends.
|
|
@@ -1236,7 +1282,9 @@ async function verify(config, request, options) {
|
|
|
1236
1282
|
fulfilment: apiResponse.fulfilment,
|
|
1237
1283
|
mandates: apiResponse.mandates,
|
|
1238
1284
|
kyaToken: apiResponse.kyaToken,
|
|
1239
|
-
aep: apiResponse.aep
|
|
1285
|
+
aep: apiResponse.aep,
|
|
1286
|
+
// 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
|
|
1287
|
+
warnings: apiResponse.warnings
|
|
1240
1288
|
};
|
|
1241
1289
|
return result2;
|
|
1242
1290
|
}
|
|
@@ -1304,7 +1352,9 @@ async function verify(config, request, options) {
|
|
|
1304
1352
|
// 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
|
|
1305
1353
|
mandates: apiResponse.mandates,
|
|
1306
1354
|
kyaToken: apiResponse.kyaToken,
|
|
1307
|
-
aep: apiResponse.aep
|
|
1355
|
+
aep: apiResponse.aep,
|
|
1356
|
+
// 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
|
|
1357
|
+
warnings: apiResponse.warnings
|
|
1308
1358
|
};
|
|
1309
1359
|
if (result.recommendation === "deny") {
|
|
1310
1360
|
result.policyAllowed = false;
|
|
@@ -1330,8 +1380,18 @@ async function verify(config, request, options) {
|
|
|
1330
1380
|
cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
|
|
1331
1381
|
}
|
|
1332
1382
|
}
|
|
1383
|
+
notifyVerificationListeners(request, result);
|
|
1333
1384
|
return result;
|
|
1334
1385
|
}
|
|
1386
|
+
var verificationListeners = /* @__PURE__ */ new Set();
|
|
1387
|
+
function notifyVerificationListeners(request, result) {
|
|
1388
|
+
for (const listener of verificationListeners) {
|
|
1389
|
+
try {
|
|
1390
|
+
listener(result, request);
|
|
1391
|
+
} catch {
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1335
1395
|
async function recordDecision(config, sessionId, decision, reason) {
|
|
1336
1396
|
const headers = { "Content-Type": "application/json" };
|
|
1337
1397
|
if (config.apiKey) {
|
|
@@ -1346,7 +1406,7 @@ async function recordDecision(config, sessionId, decision, reason) {
|
|
|
1346
1406
|
});
|
|
1347
1407
|
}
|
|
1348
1408
|
var refusedPolicyReads = /* @__PURE__ */ new Set();
|
|
1349
|
-
async function fetchRoutes(config, counterpartyId) {
|
|
1409
|
+
async function fetchRoutes(config, counterpartyId, options = {}) {
|
|
1350
1410
|
if (!counterpartyId) return null;
|
|
1351
1411
|
const headers = { "Content-Type": "application/json" };
|
|
1352
1412
|
if (config.apiKey) {
|
|
@@ -1354,8 +1414,9 @@ async function fetchRoutes(config, counterpartyId) {
|
|
|
1354
1414
|
headers["X-API-Key"] = config.apiKey;
|
|
1355
1415
|
}
|
|
1356
1416
|
try {
|
|
1417
|
+
headers["X-AstraSync-SDK-Version"] = SDK_VERSION;
|
|
1357
1418
|
const response = await sdkFetch(
|
|
1358
|
-
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes
|
|
1419
|
+
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes` + (options.codeGates?.length ? `?codeGates=${options.codeGates.map(encodeURIComponent).join(",")}` : ""),
|
|
1359
1420
|
{ method: "GET", headers }
|
|
1360
1421
|
);
|
|
1361
1422
|
if (!response.ok) {
|
|
@@ -1368,6 +1429,13 @@ async function fetchRoutes(config, counterpartyId) {
|
|
|
1368
1429
|
return null;
|
|
1369
1430
|
}
|
|
1370
1431
|
const body = await response.json();
|
|
1432
|
+
const type = body.data?.counterpartyType;
|
|
1433
|
+
if (typeof type === "string" && options.onEndpointType) {
|
|
1434
|
+
try {
|
|
1435
|
+
options.onEndpointType(type);
|
|
1436
|
+
} catch {
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1371
1439
|
return body.data?.routes ?? [];
|
|
1372
1440
|
} catch {
|
|
1373
1441
|
return null;
|
|
@@ -1401,6 +1469,42 @@ async function reportCounterpartyPreCheckFailure(config, data) {
|
|
|
1401
1469
|
});
|
|
1402
1470
|
}
|
|
1403
1471
|
|
|
1472
|
+
// src/adapters/routes-cache.ts
|
|
1473
|
+
var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
|
|
1474
|
+
function createRoutesCache(config, opts = {}) {
|
|
1475
|
+
const refreshMs = opts.refreshMs ?? DEFAULT_ROUTES_REFRESH_MS;
|
|
1476
|
+
let cached = [];
|
|
1477
|
+
let lastFetchAt = 0;
|
|
1478
|
+
let refreshing = null;
|
|
1479
|
+
async function refresh() {
|
|
1480
|
+
if (!config.counterpartyId) {
|
|
1481
|
+
opts.onNoCounterparty?.();
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
const fetched = await fetchRoutes(config, config.counterpartyId, opts.fetchOptions);
|
|
1485
|
+
if (fetched) {
|
|
1486
|
+
cached = fetched;
|
|
1487
|
+
lastFetchAt = Date.now();
|
|
1488
|
+
opts.onFetched?.(fetched);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
function start() {
|
|
1492
|
+
refreshing = refresh().catch(() => void 0).finally(() => {
|
|
1493
|
+
refreshing = null;
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
start();
|
|
1497
|
+
return {
|
|
1498
|
+
async current() {
|
|
1499
|
+
if (refreshing) await refreshing.catch(() => {
|
|
1500
|
+
});
|
|
1501
|
+
if (config.counterpartyId && Date.now() - lastFetchAt > refreshMs) start();
|
|
1502
|
+
return cached;
|
|
1503
|
+
},
|
|
1504
|
+
peek: () => cached
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1404
1508
|
// src/transport/http.ts
|
|
1405
1509
|
var HEADER_PREFIX = "X-Astra-";
|
|
1406
1510
|
function extractHttpCredentials(headers) {
|
|
@@ -1550,6 +1654,20 @@ function resolveHttpPdlss(input) {
|
|
|
1550
1654
|
}
|
|
1551
1655
|
return { purpose, action, purposeSource, actionSource };
|
|
1552
1656
|
}
|
|
1657
|
+
function wirePurposeSource(source) {
|
|
1658
|
+
switch (source) {
|
|
1659
|
+
case "route_config":
|
|
1660
|
+
return "route_config";
|
|
1661
|
+
case "header":
|
|
1662
|
+
case "legacy_header":
|
|
1663
|
+
case "query":
|
|
1664
|
+
return "header";
|
|
1665
|
+
case "custom_extractor":
|
|
1666
|
+
return "body";
|
|
1667
|
+
default:
|
|
1668
|
+
return "default";
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1553
1671
|
|
|
1554
1672
|
// src/adapters/approval-gate.ts
|
|
1555
1673
|
var APPROVAL_REASON = "Transaction is above the autonomous limit and requires human approval. The agent owner can approve or deny this transaction in the AstraSync dashboard.";
|
|
@@ -2350,7 +2468,6 @@ function defaultOnDenied(result, _req, res) {
|
|
|
2350
2468
|
}
|
|
2351
2469
|
});
|
|
2352
2470
|
}
|
|
2353
|
-
var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
|
|
2354
2471
|
function createMiddleware(options) {
|
|
2355
2472
|
if ("routes" in options) {
|
|
2356
2473
|
console.warn(
|
|
@@ -2366,7 +2483,7 @@ function createMiddleware(options) {
|
|
|
2366
2483
|
recordDecisions,
|
|
2367
2484
|
enableRuntimeChallenge = true,
|
|
2368
2485
|
routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
|
|
2369
|
-
failOnError = "
|
|
2486
|
+
failOnError = "closed",
|
|
2370
2487
|
caseInsensitiveRouteMatch = false,
|
|
2371
2488
|
anonymousBeacon = true,
|
|
2372
2489
|
trustVerifiedHop = false,
|
|
@@ -2390,26 +2507,19 @@ function createMiddleware(options) {
|
|
|
2390
2507
|
rawHeaders: req.headers
|
|
2391
2508
|
});
|
|
2392
2509
|
} : void 0;
|
|
2393
|
-
let cachedRoutes = [];
|
|
2394
|
-
let lastFetchAt = 0;
|
|
2395
|
-
let refreshing = null;
|
|
2396
2510
|
let warnedNoCounterparty = false;
|
|
2397
2511
|
let warnedEmptyRoutes = false;
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
);
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
if (fetched) {
|
|
2410
|
-
cachedRoutes = fetched;
|
|
2411
|
-
lastFetchAt = Date.now();
|
|
2412
|
-
if (cachedRoutes.length === 0 && !warnedEmptyRoutes) {
|
|
2512
|
+
const routesCache = createRoutesCache(config, {
|
|
2513
|
+
refreshMs: routesRefreshMs,
|
|
2514
|
+
onNoCounterparty: () => {
|
|
2515
|
+
if (warnedNoCounterparty) return;
|
|
2516
|
+
console.warn(
|
|
2517
|
+
"[VerificationGateway] No counterpartyId configured \u2014 falling through (allow all). Per-route policy lives in the AstraSync dashboard now; register the endpoint and set counterpartyId in your middleware config to enforce policy."
|
|
2518
|
+
);
|
|
2519
|
+
warnedNoCounterparty = true;
|
|
2520
|
+
},
|
|
2521
|
+
onFetched: (routes) => {
|
|
2522
|
+
if (routes.length === 0 && !warnedEmptyRoutes) {
|
|
2413
2523
|
const dashboard = config.dashboardUrl ?? "https://astrasync.ai/dashboard";
|
|
2414
2524
|
console.warn(
|
|
2415
2525
|
`[VerificationGateway] No route policy configured for ${config.counterpartyId}. Gateway is in pass-through mode for ALL traffic until you add at least one route. Configure at ${dashboard}/dashboard/endpoints/${config.counterpartyId}/routes`
|
|
@@ -2417,9 +2527,6 @@ function createMiddleware(options) {
|
|
|
2417
2527
|
warnedEmptyRoutes = true;
|
|
2418
2528
|
}
|
|
2419
2529
|
}
|
|
2420
|
-
}
|
|
2421
|
-
refreshing = refreshRoutes().finally(() => {
|
|
2422
|
-
refreshing = null;
|
|
2423
2530
|
});
|
|
2424
2531
|
return async (req, res, next) => {
|
|
2425
2532
|
try {
|
|
@@ -2427,15 +2534,9 @@ function createMiddleware(options) {
|
|
|
2427
2534
|
if (shouldSkip) {
|
|
2428
2535
|
return next();
|
|
2429
2536
|
}
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
}
|
|
2434
|
-
if (config.counterpartyId && Date.now() - lastFetchAt > routesRefreshMs) {
|
|
2435
|
-
refreshing = refreshRoutes().finally(() => {
|
|
2436
|
-
refreshing = null;
|
|
2437
|
-
});
|
|
2438
|
-
}
|
|
2537
|
+
const cachedRoutes = (await routesCache.current()).filter(
|
|
2538
|
+
(r) => typeof r.pattern === "string" && !r.tool
|
|
2539
|
+
);
|
|
2439
2540
|
const correlationId = req.headers["x-request-id"] || req.headers["x-correlation-id"];
|
|
2440
2541
|
const matchedRoute = findRouteConfig(cachedRoutes, req.path, req.method, {
|
|
2441
2542
|
caseInsensitive: caseInsensitiveRouteMatch,
|
|
@@ -2559,6 +2660,12 @@ function createMiddleware(options) {
|
|
|
2559
2660
|
...commerceArtifacts && { commerceArtifacts },
|
|
2560
2661
|
purpose,
|
|
2561
2662
|
action: pdlssPair.action,
|
|
2663
|
+
// 5.19.0: the source + the request line let verify-access check a
|
|
2664
|
+
// route purpose against the stored rule (item 20: an MPP paid leg
|
|
2665
|
+
// keeps `shopping.purchase` instead of `commerce.payment.execute`).
|
|
2666
|
+
purposeSource: wirePurposeSource(pdlssPair.purposeSource),
|
|
2667
|
+
requestMethod: req.method,
|
|
2668
|
+
requestPath: req.path,
|
|
2562
2669
|
resource: req.path,
|
|
2563
2670
|
createSession: shouldRecordDecisions,
|
|
2564
2671
|
counterpartyUrl,
|
|
@@ -2607,14 +2714,14 @@ function createMiddleware(options) {
|
|
|
2607
2714
|
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
2608
2715
|
res.setHeader("X-Astra-Gateway-Reason", "evaluated-not-enforced");
|
|
2609
2716
|
}
|
|
2610
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2717
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2611
2718
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
2612
2719
|
});
|
|
2613
2720
|
}
|
|
2614
2721
|
return next();
|
|
2615
2722
|
}
|
|
2616
2723
|
if (!result.policyAllowed) {
|
|
2617
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2724
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2618
2725
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
2619
2726
|
});
|
|
2620
2727
|
}
|
|
@@ -2627,7 +2734,7 @@ function createMiddleware(options) {
|
|
|
2627
2734
|
}
|
|
2628
2735
|
if (requiresHumanApproval(result)) {
|
|
2629
2736
|
annotateApprovalRequired(result);
|
|
2630
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2737
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2631
2738
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
2632
2739
|
});
|
|
2633
2740
|
}
|
|
@@ -2636,7 +2743,8 @@ function createMiddleware(options) {
|
|
|
2636
2743
|
return;
|
|
2637
2744
|
}
|
|
2638
2745
|
if (routeConfig.minTrustScore && result.agent) {
|
|
2639
|
-
|
|
2746
|
+
const score = result.agent.trustScore;
|
|
2747
|
+
if (typeof score !== "number" || score < routeConfig.minTrustScore) {
|
|
2640
2748
|
const trustFailure = {
|
|
2641
2749
|
dimension: "endpoint.trust",
|
|
2642
2750
|
message: "Trust below the route requirement for this endpoint.",
|
|
@@ -2651,7 +2759,7 @@ function createMiddleware(options) {
|
|
|
2651
2759
|
documentationUrl: wellKnownUrls.documentationUrl
|
|
2652
2760
|
};
|
|
2653
2761
|
}
|
|
2654
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2762
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2655
2763
|
recordDecision(config, sessionId, "denied", trustFailure.message).catch(() => {
|
|
2656
2764
|
});
|
|
2657
2765
|
}
|
|
@@ -2660,7 +2768,7 @@ function createMiddleware(options) {
|
|
|
2660
2768
|
return;
|
|
2661
2769
|
}
|
|
2662
2770
|
}
|
|
2663
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2771
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2664
2772
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
2665
2773
|
});
|
|
2666
2774
|
}
|