@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
|
@@ -452,7 +452,7 @@ function routePolicyOf(route) {
|
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
// src/version.ts
|
|
455
|
-
var SDK_VERSION = "5.
|
|
455
|
+
var SDK_VERSION = "5.20.0";
|
|
456
456
|
|
|
457
457
|
// src/http.ts
|
|
458
458
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -770,7 +770,12 @@ function getCacheKey(request, counterpartyId) {
|
|
|
770
770
|
// its start_checkout quote was served the cached quote-leg grant (no
|
|
771
771
|
// settlementOutcome) and never reached the backend. Same F-A1-07 bug class.
|
|
772
772
|
request.commercePhase || "",
|
|
773
|
-
request.checkoutSessionId || ""
|
|
773
|
+
request.checkoutSessionId || "",
|
|
774
|
+
// 5.19.0: a route_config purpose claim is checked server-side against
|
|
775
|
+
// the stored rule for this method + path, so it changes the verdict.
|
|
776
|
+
request.purposeSource || "",
|
|
777
|
+
request.requestMethod || "",
|
|
778
|
+
request.requestPath || ""
|
|
774
779
|
].join("|");
|
|
775
780
|
}
|
|
776
781
|
function getCachedResult(request, counterpartyId) {
|
|
@@ -962,6 +967,9 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
962
967
|
if (requestData.enableRuntimeChallenge)
|
|
963
968
|
body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
|
|
964
969
|
if (requestData.routePolicy) body.routePolicy = requestData.routePolicy;
|
|
970
|
+
if (config.actingProof?.connectorToken) {
|
|
971
|
+
body.actingProof = { connectorToken: config.actingProof.connectorToken };
|
|
972
|
+
}
|
|
965
973
|
if (requestData.approvalHeldByRoute) body.approvalHeldByRoute = true;
|
|
966
974
|
if (requestData.createSession) body.createSession = requestData.createSession;
|
|
967
975
|
if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
|
|
@@ -978,6 +986,11 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
978
986
|
if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
|
|
979
987
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
980
988
|
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
989
|
+
if (requestData.purposeSource) body.purposeSource = requestData.purposeSource;
|
|
990
|
+
if (requestData.agentArtifacts) body.agentArtifacts = requestData.agentArtifacts;
|
|
991
|
+
if (requestData.metadata) body.metadata = requestData.metadata;
|
|
992
|
+
if (requestData.requestMethod) body.requestMethod = requestData.requestMethod;
|
|
993
|
+
if (requestData.requestPath) body.requestPath = requestData.requestPath;
|
|
981
994
|
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
982
995
|
body.sdkVersion = SDK_VERSION;
|
|
983
996
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
@@ -1124,22 +1137,46 @@ async function verify(config, request, options) {
|
|
|
1124
1137
|
"[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."
|
|
1125
1138
|
);
|
|
1126
1139
|
}
|
|
1127
|
-
const uncacheable = Boolean(request.commerceArtifacts);
|
|
1140
|
+
const uncacheable = Boolean(request.commerceArtifacts) || Boolean(mergedConfig.actingProof);
|
|
1128
1141
|
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
1129
1142
|
const cached = getCachedResult(request, mergedConfig.counterpartyId);
|
|
1130
1143
|
if (cached) {
|
|
1131
1144
|
if (mergedConfig.debug) {
|
|
1132
1145
|
console.log("[VerificationGateway] Returning cached result");
|
|
1133
1146
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1147
|
+
return sharedVerdict(cached, request);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
|
|
1151
|
+
const key = getCacheKey(request, mergedConfig.counterpartyId);
|
|
1152
|
+
const pending = inflightVerifies.get(key);
|
|
1153
|
+
if (pending) return sharedVerdict(await pending, request);
|
|
1154
|
+
const flight = verifyViaApi(mergedConfig, request, urls, uncacheable);
|
|
1155
|
+
inflightVerifies.set(key, flight);
|
|
1156
|
+
try {
|
|
1157
|
+
return await flight;
|
|
1158
|
+
} finally {
|
|
1159
|
+
inflightVerifies.delete(key);
|
|
1141
1160
|
}
|
|
1142
1161
|
}
|
|
1162
|
+
return verifyViaApi(mergedConfig, request, urls, uncacheable);
|
|
1163
|
+
}
|
|
1164
|
+
var inflightVerifies = /* @__PURE__ */ new Map();
|
|
1165
|
+
var sharedVerdicts = /* @__PURE__ */ new WeakSet();
|
|
1166
|
+
function isSharedVerdict(result) {
|
|
1167
|
+
return sharedVerdicts.has(result);
|
|
1168
|
+
}
|
|
1169
|
+
function sharedVerdict(source, request) {
|
|
1170
|
+
const hit = { ...source };
|
|
1171
|
+
if (request.attemptId) {
|
|
1172
|
+
hit.attemptId = request.attemptId;
|
|
1173
|
+
} else {
|
|
1174
|
+
delete hit.attemptId;
|
|
1175
|
+
}
|
|
1176
|
+
sharedVerdicts.add(hit);
|
|
1177
|
+
return hit;
|
|
1178
|
+
}
|
|
1179
|
+
async function verifyViaApi(mergedConfig, request, urls, uncacheable) {
|
|
1143
1180
|
const enrichedRequest = { ...request };
|
|
1144
1181
|
if (!enrichedRequest.counterpartyUrl && mergedConfig.counterpartyUrl) {
|
|
1145
1182
|
enrichedRequest.counterpartyUrl = mergedConfig.counterpartyUrl;
|
|
@@ -1167,9 +1204,18 @@ async function verify(config, request, options) {
|
|
|
1167
1204
|
if (!apiResponse.access?.allowed) {
|
|
1168
1205
|
const aggregatedFailures = apiResponse.access?.failures;
|
|
1169
1206
|
const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
|
|
1207
|
+
const denyAgent = idVerifiedFromBackend && apiResponse.agent ? {
|
|
1208
|
+
astraId: apiResponse.agent.astraId,
|
|
1209
|
+
name: apiResponse.agent.name,
|
|
1210
|
+
trustScore: apiResponse.agent.trustScore,
|
|
1211
|
+
trustLevel: getTrustLevel(apiResponse.agent.trustScore),
|
|
1212
|
+
blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
|
|
1213
|
+
status: apiResponse.agent.agentStatus
|
|
1214
|
+
} : void 0;
|
|
1170
1215
|
const result2 = {
|
|
1171
1216
|
identityVerified: idVerifiedFromBackend,
|
|
1172
1217
|
policyAllowed: false,
|
|
1218
|
+
...denyAgent && { agent: denyAgent },
|
|
1173
1219
|
// 3.6.0: the server now emits top-level denialReasons on every deny
|
|
1174
1220
|
// path — prefer it verbatim; the failure-message reconstruction remains
|
|
1175
1221
|
// as the fallback for older backends.
|
|
@@ -1209,7 +1255,9 @@ async function verify(config, request, options) {
|
|
|
1209
1255
|
fulfilment: apiResponse.fulfilment,
|
|
1210
1256
|
mandates: apiResponse.mandates,
|
|
1211
1257
|
kyaToken: apiResponse.kyaToken,
|
|
1212
|
-
aep: apiResponse.aep
|
|
1258
|
+
aep: apiResponse.aep,
|
|
1259
|
+
// 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
|
|
1260
|
+
warnings: apiResponse.warnings
|
|
1213
1261
|
};
|
|
1214
1262
|
return result2;
|
|
1215
1263
|
}
|
|
@@ -1277,7 +1325,9 @@ async function verify(config, request, options) {
|
|
|
1277
1325
|
// 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
|
|
1278
1326
|
mandates: apiResponse.mandates,
|
|
1279
1327
|
kyaToken: apiResponse.kyaToken,
|
|
1280
|
-
aep: apiResponse.aep
|
|
1328
|
+
aep: apiResponse.aep,
|
|
1329
|
+
// 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
|
|
1330
|
+
warnings: apiResponse.warnings
|
|
1281
1331
|
};
|
|
1282
1332
|
if (result.recommendation === "deny") {
|
|
1283
1333
|
result.policyAllowed = false;
|
|
@@ -1303,8 +1353,18 @@ async function verify(config, request, options) {
|
|
|
1303
1353
|
cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
|
|
1304
1354
|
}
|
|
1305
1355
|
}
|
|
1356
|
+
notifyVerificationListeners(request, result);
|
|
1306
1357
|
return result;
|
|
1307
1358
|
}
|
|
1359
|
+
var verificationListeners = /* @__PURE__ */ new Set();
|
|
1360
|
+
function notifyVerificationListeners(request, result) {
|
|
1361
|
+
for (const listener of verificationListeners) {
|
|
1362
|
+
try {
|
|
1363
|
+
listener(result, request);
|
|
1364
|
+
} catch {
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1308
1368
|
async function recordDecision(config, sessionId, decision, reason) {
|
|
1309
1369
|
const headers = { "Content-Type": "application/json" };
|
|
1310
1370
|
if (config.apiKey) {
|
|
@@ -1319,7 +1379,7 @@ async function recordDecision(config, sessionId, decision, reason) {
|
|
|
1319
1379
|
});
|
|
1320
1380
|
}
|
|
1321
1381
|
var refusedPolicyReads = /* @__PURE__ */ new Set();
|
|
1322
|
-
async function fetchRoutes(config, counterpartyId) {
|
|
1382
|
+
async function fetchRoutes(config, counterpartyId, options = {}) {
|
|
1323
1383
|
if (!counterpartyId) return null;
|
|
1324
1384
|
const headers = { "Content-Type": "application/json" };
|
|
1325
1385
|
if (config.apiKey) {
|
|
@@ -1327,8 +1387,9 @@ async function fetchRoutes(config, counterpartyId) {
|
|
|
1327
1387
|
headers["X-API-Key"] = config.apiKey;
|
|
1328
1388
|
}
|
|
1329
1389
|
try {
|
|
1390
|
+
headers["X-AstraSync-SDK-Version"] = SDK_VERSION;
|
|
1330
1391
|
const response = await sdkFetch(
|
|
1331
|
-
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes
|
|
1392
|
+
`${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes` + (options.codeGates?.length ? `?codeGates=${options.codeGates.map(encodeURIComponent).join(",")}` : ""),
|
|
1332
1393
|
{ method: "GET", headers }
|
|
1333
1394
|
);
|
|
1334
1395
|
if (!response.ok) {
|
|
@@ -1341,6 +1402,13 @@ async function fetchRoutes(config, counterpartyId) {
|
|
|
1341
1402
|
return null;
|
|
1342
1403
|
}
|
|
1343
1404
|
const body = await response.json();
|
|
1405
|
+
const type = body.data?.counterpartyType;
|
|
1406
|
+
if (typeof type === "string" && options.onEndpointType) {
|
|
1407
|
+
try {
|
|
1408
|
+
options.onEndpointType(type);
|
|
1409
|
+
} catch {
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1344
1412
|
return body.data?.routes ?? [];
|
|
1345
1413
|
} catch {
|
|
1346
1414
|
return null;
|
|
@@ -1374,6 +1442,42 @@ async function reportCounterpartyPreCheckFailure(config, data) {
|
|
|
1374
1442
|
});
|
|
1375
1443
|
}
|
|
1376
1444
|
|
|
1445
|
+
// src/adapters/routes-cache.ts
|
|
1446
|
+
var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
|
|
1447
|
+
function createRoutesCache(config, opts = {}) {
|
|
1448
|
+
const refreshMs = opts.refreshMs ?? DEFAULT_ROUTES_REFRESH_MS;
|
|
1449
|
+
let cached = [];
|
|
1450
|
+
let lastFetchAt = 0;
|
|
1451
|
+
let refreshing = null;
|
|
1452
|
+
async function refresh() {
|
|
1453
|
+
if (!config.counterpartyId) {
|
|
1454
|
+
opts.onNoCounterparty?.();
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
const fetched = await fetchRoutes(config, config.counterpartyId, opts.fetchOptions);
|
|
1458
|
+
if (fetched) {
|
|
1459
|
+
cached = fetched;
|
|
1460
|
+
lastFetchAt = Date.now();
|
|
1461
|
+
opts.onFetched?.(fetched);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
function start() {
|
|
1465
|
+
refreshing = refresh().catch(() => void 0).finally(() => {
|
|
1466
|
+
refreshing = null;
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
start();
|
|
1470
|
+
return {
|
|
1471
|
+
async current() {
|
|
1472
|
+
if (refreshing) await refreshing.catch(() => {
|
|
1473
|
+
});
|
|
1474
|
+
if (config.counterpartyId && Date.now() - lastFetchAt > refreshMs) start();
|
|
1475
|
+
return cached;
|
|
1476
|
+
},
|
|
1477
|
+
peek: () => cached
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1377
1481
|
// src/transport/http.ts
|
|
1378
1482
|
var HEADER_PREFIX = "X-Astra-";
|
|
1379
1483
|
function extractHttpCredentials(headers) {
|
|
@@ -1523,6 +1627,20 @@ function resolveHttpPdlss(input) {
|
|
|
1523
1627
|
}
|
|
1524
1628
|
return { purpose, action, purposeSource, actionSource };
|
|
1525
1629
|
}
|
|
1630
|
+
function wirePurposeSource(source) {
|
|
1631
|
+
switch (source) {
|
|
1632
|
+
case "route_config":
|
|
1633
|
+
return "route_config";
|
|
1634
|
+
case "header":
|
|
1635
|
+
case "legacy_header":
|
|
1636
|
+
case "query":
|
|
1637
|
+
return "header";
|
|
1638
|
+
case "custom_extractor":
|
|
1639
|
+
return "body";
|
|
1640
|
+
default:
|
|
1641
|
+
return "default";
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1526
1644
|
|
|
1527
1645
|
// src/adapters/approval-gate.ts
|
|
1528
1646
|
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.";
|
|
@@ -2323,7 +2441,6 @@ function defaultOnDenied(result, _req, res) {
|
|
|
2323
2441
|
}
|
|
2324
2442
|
});
|
|
2325
2443
|
}
|
|
2326
|
-
var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
|
|
2327
2444
|
function createMiddleware(options) {
|
|
2328
2445
|
if ("routes" in options) {
|
|
2329
2446
|
console.warn(
|
|
@@ -2339,7 +2456,7 @@ function createMiddleware(options) {
|
|
|
2339
2456
|
recordDecisions,
|
|
2340
2457
|
enableRuntimeChallenge = true,
|
|
2341
2458
|
routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
|
|
2342
|
-
failOnError = "
|
|
2459
|
+
failOnError = "closed",
|
|
2343
2460
|
caseInsensitiveRouteMatch = false,
|
|
2344
2461
|
anonymousBeacon = true,
|
|
2345
2462
|
trustVerifiedHop = false,
|
|
@@ -2363,26 +2480,19 @@ function createMiddleware(options) {
|
|
|
2363
2480
|
rawHeaders: req.headers
|
|
2364
2481
|
});
|
|
2365
2482
|
} : void 0;
|
|
2366
|
-
let cachedRoutes = [];
|
|
2367
|
-
let lastFetchAt = 0;
|
|
2368
|
-
let refreshing = null;
|
|
2369
2483
|
let warnedNoCounterparty = false;
|
|
2370
2484
|
let warnedEmptyRoutes = false;
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
);
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
if (fetched) {
|
|
2383
|
-
cachedRoutes = fetched;
|
|
2384
|
-
lastFetchAt = Date.now();
|
|
2385
|
-
if (cachedRoutes.length === 0 && !warnedEmptyRoutes) {
|
|
2485
|
+
const routesCache = createRoutesCache(config, {
|
|
2486
|
+
refreshMs: routesRefreshMs,
|
|
2487
|
+
onNoCounterparty: () => {
|
|
2488
|
+
if (warnedNoCounterparty) return;
|
|
2489
|
+
console.warn(
|
|
2490
|
+
"[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."
|
|
2491
|
+
);
|
|
2492
|
+
warnedNoCounterparty = true;
|
|
2493
|
+
},
|
|
2494
|
+
onFetched: (routes) => {
|
|
2495
|
+
if (routes.length === 0 && !warnedEmptyRoutes) {
|
|
2386
2496
|
const dashboard = config.dashboardUrl ?? "https://astrasync.ai/dashboard";
|
|
2387
2497
|
console.warn(
|
|
2388
2498
|
`[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`
|
|
@@ -2390,9 +2500,6 @@ function createMiddleware(options) {
|
|
|
2390
2500
|
warnedEmptyRoutes = true;
|
|
2391
2501
|
}
|
|
2392
2502
|
}
|
|
2393
|
-
}
|
|
2394
|
-
refreshing = refreshRoutes().finally(() => {
|
|
2395
|
-
refreshing = null;
|
|
2396
2503
|
});
|
|
2397
2504
|
return async (req, res, next) => {
|
|
2398
2505
|
try {
|
|
@@ -2400,15 +2507,9 @@ function createMiddleware(options) {
|
|
|
2400
2507
|
if (shouldSkip) {
|
|
2401
2508
|
return next();
|
|
2402
2509
|
}
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
}
|
|
2407
|
-
if (config.counterpartyId && Date.now() - lastFetchAt > routesRefreshMs) {
|
|
2408
|
-
refreshing = refreshRoutes().finally(() => {
|
|
2409
|
-
refreshing = null;
|
|
2410
|
-
});
|
|
2411
|
-
}
|
|
2510
|
+
const cachedRoutes = (await routesCache.current()).filter(
|
|
2511
|
+
(r) => typeof r.pattern === "string" && !r.tool
|
|
2512
|
+
);
|
|
2412
2513
|
const correlationId = req.headers["x-request-id"] || req.headers["x-correlation-id"];
|
|
2413
2514
|
const matchedRoute = findRouteConfig(cachedRoutes, req.path, req.method, {
|
|
2414
2515
|
caseInsensitive: caseInsensitiveRouteMatch,
|
|
@@ -2532,6 +2633,12 @@ function createMiddleware(options) {
|
|
|
2532
2633
|
...commerceArtifacts && { commerceArtifacts },
|
|
2533
2634
|
purpose,
|
|
2534
2635
|
action: pdlssPair.action,
|
|
2636
|
+
// 5.19.0: the source + the request line let verify-access check a
|
|
2637
|
+
// route purpose against the stored rule (item 20: an MPP paid leg
|
|
2638
|
+
// keeps `shopping.purchase` instead of `commerce.payment.execute`).
|
|
2639
|
+
purposeSource: wirePurposeSource(pdlssPair.purposeSource),
|
|
2640
|
+
requestMethod: req.method,
|
|
2641
|
+
requestPath: req.path,
|
|
2535
2642
|
resource: req.path,
|
|
2536
2643
|
createSession: shouldRecordDecisions,
|
|
2537
2644
|
counterpartyUrl,
|
|
@@ -2580,14 +2687,14 @@ function createMiddleware(options) {
|
|
|
2580
2687
|
res.setHeader("X-Astra-Gateway-Mode", "enforced");
|
|
2581
2688
|
res.setHeader("X-Astra-Gateway-Reason", "evaluated-not-enforced");
|
|
2582
2689
|
}
|
|
2583
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2690
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2584
2691
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
2585
2692
|
});
|
|
2586
2693
|
}
|
|
2587
2694
|
return next();
|
|
2588
2695
|
}
|
|
2589
2696
|
if (!result.policyAllowed) {
|
|
2590
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2697
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2591
2698
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
2592
2699
|
});
|
|
2593
2700
|
}
|
|
@@ -2600,7 +2707,7 @@ function createMiddleware(options) {
|
|
|
2600
2707
|
}
|
|
2601
2708
|
if (requiresHumanApproval(result)) {
|
|
2602
2709
|
annotateApprovalRequired(result);
|
|
2603
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2710
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2604
2711
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
2605
2712
|
});
|
|
2606
2713
|
}
|
|
@@ -2609,7 +2716,8 @@ function createMiddleware(options) {
|
|
|
2609
2716
|
return;
|
|
2610
2717
|
}
|
|
2611
2718
|
if (routeConfig.minTrustScore && result.agent) {
|
|
2612
|
-
|
|
2719
|
+
const score = result.agent.trustScore;
|
|
2720
|
+
if (typeof score !== "number" || score < routeConfig.minTrustScore) {
|
|
2613
2721
|
const trustFailure = {
|
|
2614
2722
|
dimension: "endpoint.trust",
|
|
2615
2723
|
message: "Trust below the route requirement for this endpoint.",
|
|
@@ -2624,7 +2732,7 @@ function createMiddleware(options) {
|
|
|
2624
2732
|
documentationUrl: wellKnownUrls.documentationUrl
|
|
2625
2733
|
};
|
|
2626
2734
|
}
|
|
2627
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2735
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2628
2736
|
recordDecision(config, sessionId, "denied", trustFailure.message).catch(() => {
|
|
2629
2737
|
});
|
|
2630
2738
|
}
|
|
@@ -2633,7 +2741,7 @@ function createMiddleware(options) {
|
|
|
2633
2741
|
return;
|
|
2634
2742
|
}
|
|
2635
2743
|
}
|
|
2636
|
-
if (shouldRecordDecisions && sessionId) {
|
|
2744
|
+
if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
|
|
2637
2745
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
2638
2746
|
});
|
|
2639
2747
|
}
|