@astrasyncai/verification-gateway 2.3.7 → 2.3.9
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 +93 -10
- 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 +81 -7
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +81 -7
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +84 -12
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +84 -12
- 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 +40 -6
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +40 -6
- 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 +40 -6
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +40 -6
- 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/browser/background.js +39 -5
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +39 -5
- 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 +39 -5
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +39 -5
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/{express-D9oRsseg.d.mts → express-BiB51d5t.d.mts} +1 -1
- package/dist/{express-DMSIl20m.d.ts → express-D6tEDU08.d.ts} +1 -1
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +39 -5
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +39 -5
- 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-EwUWXC5T.d.ts → index-8DFMpITk.d.ts} +1 -1
- package/dist/{index-YNPs800Z.d.mts → index-B--6fiDp.d.mts} +1 -1
- package/dist/{index-Bn_7eGjb.d.mts → index-CAykfMWK.d.mts} +1 -1
- package/dist/{index-BtU9yFda.d.ts → index-Yt02MRyu.d.ts} +1 -1
- package/dist/index.d.mts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +87 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +87 -13
- 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-B5ZBpHra.d.ts → nextjs-CK5F_tVZ.d.ts} +1 -1
- package/dist/{nextjs-BLtjRbc-.d.mts → nextjs-CpxqfQqD.d.mts} +1 -1
- package/dist/{sdk-BhkxvqnK.d.mts → sdk-BMvauMgP.d.ts} +9 -2
- package/dist/{sdk-YmE3RG8n.d.ts → sdk-yJjO7yzn.d.mts} +9 -2
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/{types-DxY5zt4z.d.mts → types-CKafuHDn.d.mts} +1 -1
- package/dist/{types-Bxqj1sKY.d.mts → types-UYT4GdPW.d.mts} +42 -4
- package/dist/{types-Bxqj1sKY.d.ts → types-UYT4GdPW.d.ts} +42 -4
- package/dist/{types-BecRpozv.d.ts → types-ppkhdldJ.d.ts} +1 -1
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +3 -3
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/index.mjs +3 -3
- package/dist/ui/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,15 +40,16 @@ import { createMiddleware } from '@astrasyncai/verification-gateway/express';
|
|
|
40
40
|
|
|
41
41
|
const app = express();
|
|
42
42
|
|
|
43
|
+
// v2.3.7+ — per-route policy lives in the AstraSync dashboard.
|
|
44
|
+
// The SDK fetches it on init via counterpartyId; do NOT pass routes here.
|
|
43
45
|
app.use(
|
|
44
46
|
createMiddleware({
|
|
45
47
|
apiBaseUrl: 'https://astrasync.ai/api',
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
],
|
|
48
|
+
apiKey: process.env.ASTRASYNC_API_KEY,
|
|
49
|
+
counterpartyId: 'ASTRAE-...', // your endpoint id from the dashboard
|
|
50
|
+
setPassThroughHeader: true, // recommended for local-dev / staging
|
|
51
|
+
// — surfaces pass-through mode when
|
|
52
|
+
// no per-route policy is configured
|
|
52
53
|
})
|
|
53
54
|
);
|
|
54
55
|
```
|
|
@@ -59,13 +60,13 @@ app.use(
|
|
|
59
60
|
// middleware.ts
|
|
60
61
|
import { createMiddleware } from '@astrasyncai/verification-gateway/nextjs';
|
|
61
62
|
|
|
63
|
+
// v2.3.7+ — per-route policy lives in the AstraSync dashboard.
|
|
64
|
+
// The SDK fetches it on init via counterpartyId; do NOT pass routes here.
|
|
62
65
|
export const middleware = createMiddleware({
|
|
63
66
|
apiBaseUrl: 'https://api.astrasync.ai',
|
|
67
|
+
apiKey: process.env.ASTRASYNC_API_KEY,
|
|
68
|
+
counterpartyId: 'ASTRAE-...',
|
|
64
69
|
showCommerceShield: true,
|
|
65
|
-
routes: [
|
|
66
|
-
{ pattern: '/api/*', method: '*', minAccessLevel: 'standard' },
|
|
67
|
-
{ pattern: '/dashboard/*', method: '*', minAccessLevel: 'read-only' },
|
|
68
|
-
],
|
|
69
70
|
});
|
|
70
71
|
|
|
71
72
|
export const config = {
|
|
@@ -94,6 +95,88 @@ if (result.verified && result.accessLevel !== 'none') {
|
|
|
94
95
|
}
|
|
95
96
|
```
|
|
96
97
|
|
|
98
|
+
### Inner-hop verification (MCP → REST dedupe with X-Astra-Verified-Hop)
|
|
99
|
+
|
|
100
|
+
When an MCP tool calls an inner REST endpoint that ALSO runs the
|
|
101
|
+
verification gateway, two verify-access calls fire for the same agent in
|
|
102
|
+
the same logical request — audit gets noisy and you pay a doubled
|
|
103
|
+
round-trip. The `X-Astra-Verified-Hop` header marks the inner hop as
|
|
104
|
+
already-verified by the upstream so the inner middleware skips a
|
|
105
|
+
redundant verify-access call.
|
|
106
|
+
|
|
107
|
+
The MCP middleware emits the marker automatically on its outbound
|
|
108
|
+
response. Tool handlers calling inner REST hops need to forward it on
|
|
109
|
+
outgoing fetches; the inner middleware reads it via `parseVerifiedHop` +
|
|
110
|
+
`isVerifiedHopValidFor` and skips a duplicate verify-access if the
|
|
111
|
+
marker is fresh AND matches the agent claimed on the inner hop.
|
|
112
|
+
|
|
113
|
+
**Worked example — upstream MCP → inner REST hop:**
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// === outer MCP server ===
|
|
117
|
+
import express from 'express';
|
|
118
|
+
import { createMcpMiddleware } from '@astrasyncai/verification-gateway/mcp';
|
|
119
|
+
|
|
120
|
+
const mcp = express();
|
|
121
|
+
mcp.use(express.json());
|
|
122
|
+
mcp.use(
|
|
123
|
+
createMcpMiddleware({
|
|
124
|
+
apiBaseUrl: 'https://astrasync.ai/api',
|
|
125
|
+
apiKey: process.env.ASTRASYNC_API_KEY,
|
|
126
|
+
counterpartyId: 'ASTRAE-mcp...',
|
|
127
|
+
toolGates: { start_checkout: 'standard' },
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// MCP middleware sets X-Astra-Verified-Hop on the response automatically
|
|
132
|
+
// AND populates req.agentVerification. Tool handlers can read both.
|
|
133
|
+
mcp.post('/mcp', async (req, res) => {
|
|
134
|
+
const v = req.agentVerification!;
|
|
135
|
+
// Forward the verified-hop marker on outgoing inner-hop calls.
|
|
136
|
+
// Build it from the same fields the middleware uses on the response.
|
|
137
|
+
const { serializeVerifiedHop, MCP_VERIFIED_HOP_HEADER } =
|
|
138
|
+
await import('@astrasyncai/verification-gateway/mcp');
|
|
139
|
+
const hop = serializeVerifiedHop({
|
|
140
|
+
astraId: v.agent!.astraId,
|
|
141
|
+
sessionId: v.sessionId,
|
|
142
|
+
checkedAt: Date.now(),
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const inner = await fetch('http://internal/api/checkout/items', {
|
|
146
|
+
method: 'POST',
|
|
147
|
+
headers: {
|
|
148
|
+
'Content-Type': 'application/json',
|
|
149
|
+
'X-Astra-Id': v.agent!.astraId, // identity marker
|
|
150
|
+
[MCP_VERIFIED_HOP_HEADER]: hop, // verified-hop dedupe marker
|
|
151
|
+
},
|
|
152
|
+
body: JSON.stringify({ sku: 'sku_42' }),
|
|
153
|
+
});
|
|
154
|
+
res.status(inner.status).json(await inner.json());
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// === inner REST hop (same fleet) ===
|
|
158
|
+
import { createMiddleware } from '@astrasyncai/verification-gateway/express';
|
|
159
|
+
|
|
160
|
+
const rest = express();
|
|
161
|
+
rest.use(
|
|
162
|
+
createMiddleware({
|
|
163
|
+
apiBaseUrl: 'https://astrasync.ai/api',
|
|
164
|
+
apiKey: process.env.ASTRASYNC_API_KEY,
|
|
165
|
+
counterpartyId: 'ASTRAE-rest...',
|
|
166
|
+
trustVerifiedHop: true, // accept the dedupe marker
|
|
167
|
+
verifiedHopMaxAgeMs: 60_000, // 60s default; tighten for high-stakes
|
|
168
|
+
})
|
|
169
|
+
);
|
|
170
|
+
// Inner middleware reads X-Astra-Verified-Hop, validates via
|
|
171
|
+
// parseVerifiedHop + isVerifiedHopValidFor, and skips verify-access
|
|
172
|
+
// when the marker is fresh AND its astraId matches the X-Astra-Id on
|
|
173
|
+
// this request.
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Important:** the marker is NOT proof of identity by itself — pair it
|
|
177
|
+
with `X-Astra-Id` so the inner middleware can verify the marker matches
|
|
178
|
+
the claimed agent. The marker only gates the dedupe-skip decision.
|
|
179
|
+
|
|
97
180
|
## Access Levels
|
|
98
181
|
|
|
99
182
|
| Level | Description |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AstraSyncGateway } from '../gateway/gateway.mjs';
|
|
2
|
-
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-
|
|
3
|
-
import '../types-
|
|
2
|
+
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-CKafuHDn.mjs';
|
|
3
|
+
import '../types-UYT4GdPW.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* PlatformAdapter Interface
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AstraSyncGateway } from '../gateway/gateway.js';
|
|
2
|
-
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-
|
|
3
|
-
import '../types-
|
|
2
|
+
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-ppkhdldJ.js';
|
|
3
|
+
import '../types-UYT4GdPW.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* PlatformAdapter Interface
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'express';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMiddleware, a as extractAstraSyncCredentials } from '../express-
|
|
2
|
+
import '../types-UYT4GdPW.mjs';
|
|
3
|
+
export { c as createMiddleware, a as extractAstraSyncCredentials } from '../express-BiB51d5t.mjs';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'express';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMiddleware, a as extractAstraSyncCredentials } from '../express-
|
|
2
|
+
import '../types-UYT4GdPW.js';
|
|
3
|
+
export { c as createMiddleware, a as extractAstraSyncCredentials } from '../express-D6tEDU08.js';
|
package/dist/adapters/express.js
CHANGED
|
@@ -28,7 +28,7 @@ module.exports = __toCommonJS(express_exports);
|
|
|
28
28
|
// src/access-levels.ts
|
|
29
29
|
var ACCESS_LEVEL_HIERARCHY = {
|
|
30
30
|
none: 0,
|
|
31
|
-
|
|
31
|
+
restricted: 1,
|
|
32
32
|
"read-only": 2,
|
|
33
33
|
standard: 3,
|
|
34
34
|
full: 4,
|
|
@@ -47,7 +47,11 @@ function hasMinimumAccess(actual, required) {
|
|
|
47
47
|
// src/verify.ts
|
|
48
48
|
var DEFAULT_CONFIG = {
|
|
49
49
|
apiBaseUrl: "https://astrasync.ai/api",
|
|
50
|
-
|
|
50
|
+
// v2.3.9 (defect #30): default for unconfigured callers is `'none'` (no
|
|
51
|
+
// access). Pre-rename this defaulted to `'guidance'`, which combined with
|
|
52
|
+
// a route gated at `'guidance'` to silently let unverified traffic
|
|
53
|
+
// through (`hasMinimumAccess('guidance', 'guidance') === true`).
|
|
54
|
+
defaultAccessLevel: "none",
|
|
51
55
|
// minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.
|
|
52
56
|
cacheTtl: 300,
|
|
53
57
|
// 5 minutes
|
|
@@ -140,7 +144,12 @@ function createGuidanceResponse(config, reason) {
|
|
|
140
144
|
};
|
|
141
145
|
return {
|
|
142
146
|
verified: false,
|
|
143
|
-
|
|
147
|
+
// v2.3.9 (defect #30): denials grant `'none'`, NEVER a positive band.
|
|
148
|
+
// Adapters additionally short-circuit on `verified === false` before
|
|
149
|
+
// the gate check, but the access level still has to be honest at the
|
|
150
|
+
// data layer so downstream consumers (SDK adapters in other languages,
|
|
151
|
+
// custom integrations) inherit the correct semantics.
|
|
152
|
+
accessLevel: "none",
|
|
144
153
|
guidance,
|
|
145
154
|
denialReasons: reason ? [reason] : ["No valid agent credentials provided"],
|
|
146
155
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
@@ -197,6 +206,23 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
197
206
|
body: JSON.stringify(body)
|
|
198
207
|
});
|
|
199
208
|
const data = await response.json();
|
|
209
|
+
if (response.status === 410) {
|
|
210
|
+
return {
|
|
211
|
+
success: true,
|
|
212
|
+
access: {
|
|
213
|
+
allowed: false,
|
|
214
|
+
accessLevel: "none",
|
|
215
|
+
reason: "endpoint_deactivated",
|
|
216
|
+
failures: [
|
|
217
|
+
{
|
|
218
|
+
dimension: "endpoint.deactivated",
|
|
219
|
+
message: typeof data?.message === "string" ? data.message : "Endpoint has been deactivated",
|
|
220
|
+
guidance: typeof data?.guidance === "string" ? data.guidance : "Reactivate via POST /api/endpoints/{id}/reactivate, or update the URL on the calling agent."
|
|
221
|
+
}
|
|
222
|
+
]
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
200
226
|
if (!response.ok) {
|
|
201
227
|
return {
|
|
202
228
|
success: false,
|
|
@@ -250,7 +276,14 @@ async function verify(config, request) {
|
|
|
250
276
|
const aggregatedFailures = apiResponse.access?.failures;
|
|
251
277
|
const result2 = {
|
|
252
278
|
verified: false,
|
|
253
|
-
|
|
279
|
+
// v2.3.9 (defect #30): denials grant `'none'`, NEVER a positive band.
|
|
280
|
+
// Pre-rename this hardcoded `'guidance'`, which conflated with the
|
|
281
|
+
// colocated `guidance: {...}` help-payload object below and let
|
|
282
|
+
// denied requests pass any route gated at `'guidance'` because
|
|
283
|
+
// `hasMinimumAccess('guidance', 'guidance') === true`. Adapters now
|
|
284
|
+
// ALSO short-circuit on `verified === false` before the gate check —
|
|
285
|
+
// belt-and-braces.
|
|
286
|
+
accessLevel: "none",
|
|
254
287
|
denialReasons: aggregatedFailures && aggregatedFailures.length > 0 ? aggregatedFailures.map((f) => f.message) : apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"],
|
|
255
288
|
failures: aggregatedFailures,
|
|
256
289
|
requiresStepUp: apiResponse.access?.requiresStepUp,
|
|
@@ -306,7 +339,8 @@ async function verify(config, request) {
|
|
|
306
339
|
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
307
340
|
tokenGuidance: apiResponse.tokenGuidance,
|
|
308
341
|
recommendation: apiResponse.recommendation,
|
|
309
|
-
recommendationReasons: apiResponse.recommendationReasons
|
|
342
|
+
recommendationReasons: apiResponse.recommendationReasons,
|
|
343
|
+
warningHeader: apiResponse.warningHeader
|
|
310
344
|
};
|
|
311
345
|
if (result.recommendation === "deny") {
|
|
312
346
|
result.verified = false;
|
|
@@ -333,7 +367,7 @@ async function verify(config, request) {
|
|
|
333
367
|
}
|
|
334
368
|
return result;
|
|
335
369
|
}
|
|
336
|
-
async function recordDecision(config, sessionId, decision, reason) {
|
|
370
|
+
async function recordDecision(config, sessionId, decision, reason, override) {
|
|
337
371
|
const headers = { "Content-Type": "application/json" };
|
|
338
372
|
if (config.apiKey) {
|
|
339
373
|
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
@@ -342,7 +376,16 @@ async function recordDecision(config, sessionId, decision, reason) {
|
|
|
342
376
|
await fetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
|
|
343
377
|
method: "POST",
|
|
344
378
|
headers,
|
|
345
|
-
body: JSON.stringify({
|
|
379
|
+
body: JSON.stringify({
|
|
380
|
+
decision,
|
|
381
|
+
reason,
|
|
382
|
+
...override && {
|
|
383
|
+
overriddenBy: override.overriddenBy,
|
|
384
|
+
toolName: override.toolName,
|
|
385
|
+
requestedLevel: override.requestedLevel,
|
|
386
|
+
grantedLevel: override.grantedLevel
|
|
387
|
+
}
|
|
388
|
+
})
|
|
346
389
|
}).catch(() => {
|
|
347
390
|
});
|
|
348
391
|
}
|
|
@@ -540,6 +583,7 @@ function createMiddleware(options) {
|
|
|
540
583
|
let lastFetchAt = 0;
|
|
541
584
|
let refreshing = null;
|
|
542
585
|
let warnedNoCounterparty = false;
|
|
586
|
+
let warnedEmptyRoutes = false;
|
|
543
587
|
async function refreshRoutes() {
|
|
544
588
|
if (!config.counterpartyId) {
|
|
545
589
|
if (!warnedNoCounterparty) {
|
|
@@ -554,6 +598,13 @@ function createMiddleware(options) {
|
|
|
554
598
|
if (fetched) {
|
|
555
599
|
cachedRoutes = fetched;
|
|
556
600
|
lastFetchAt = Date.now();
|
|
601
|
+
if (cachedRoutes.length === 0 && !warnedEmptyRoutes) {
|
|
602
|
+
const dashboard = config.dashboardUrl ?? "https://app.astrasync.ai";
|
|
603
|
+
console.warn(
|
|
604
|
+
`[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`
|
|
605
|
+
);
|
|
606
|
+
warnedEmptyRoutes = true;
|
|
607
|
+
}
|
|
557
608
|
}
|
|
558
609
|
}
|
|
559
610
|
refreshing = refreshRoutes().finally(() => {
|
|
@@ -576,9 +627,20 @@ function createMiddleware(options) {
|
|
|
576
627
|
}
|
|
577
628
|
const routeConfig = findRouteConfig(cachedRoutes, req.path, req.method);
|
|
578
629
|
if (!routeConfig) {
|
|
630
|
+
if (config.setPassThroughHeader) {
|
|
631
|
+
res.setHeader("X-Astra-Gateway-Mode", "pass-through");
|
|
632
|
+
res.setHeader(
|
|
633
|
+
"X-Astra-Gateway-Reason",
|
|
634
|
+
cachedRoutes.length === 0 ? "no-policy" : "no-match"
|
|
635
|
+
);
|
|
636
|
+
}
|
|
579
637
|
return next();
|
|
580
638
|
}
|
|
581
639
|
if (routeConfig.minAccessLevel === "none") {
|
|
640
|
+
if (config.setPassThroughHeader) {
|
|
641
|
+
res.setHeader("X-Astra-Gateway-Mode", "pass-through");
|
|
642
|
+
res.setHeader("X-Astra-Gateway-Reason", "route-none");
|
|
643
|
+
}
|
|
582
644
|
return next();
|
|
583
645
|
}
|
|
584
646
|
const credentials = customExtractCredentials ? customExtractCredentials(req) : defaultExtractCredentials(req);
|
|
@@ -637,6 +699,14 @@ function createMiddleware(options) {
|
|
|
637
699
|
});
|
|
638
700
|
req.agentVerification = result;
|
|
639
701
|
const sessionId = result.sessionId;
|
|
702
|
+
if (!result.verified) {
|
|
703
|
+
if (shouldRecordDecisions && sessionId) {
|
|
704
|
+
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
onDenied(result, req, res);
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
640
710
|
if (!hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
|
|
641
711
|
if (shouldRecordDecisions && sessionId) {
|
|
642
712
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|
|
@@ -662,6 +732,10 @@ function createMiddleware(options) {
|
|
|
662
732
|
recordDecision(config, sessionId, "granted").catch(() => {
|
|
663
733
|
});
|
|
664
734
|
}
|
|
735
|
+
const enhancedResult = result;
|
|
736
|
+
if (enhancedResult.warningHeader) {
|
|
737
|
+
res.setHeader(enhancedResult.warningHeader.name, enhancedResult.warningHeader.value);
|
|
738
|
+
}
|
|
665
739
|
next();
|
|
666
740
|
} catch (error) {
|
|
667
741
|
console.error("[VerificationGateway] Middleware error:", error);
|