@lensmcp/cluster 1.0.0 → 1.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.lib.d.ts","sourceRoot":"","sources":["../../../../../libs/cluster/src/executors/gateway/gateway.lib.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gateway.lib.d.ts","sourceRoot":"","sources":["../../../../../libs/cluster/src/executors/gateway/gateway.lib.ts"],"names":[],"mappings":"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"}
@@ -253,6 +253,7 @@ async function startGateway(options, context) {
253
253
  const text = d.toString();
254
254
  for (const line of text.split('\n')) {
255
255
  if (/ERROR in |error TS\d+|Found \d+ error|Unhandled 'error' event|EADDRINUSE/.test(line)) {
256
+ // eslint-disable-next-line no-control-regex -- strip ANSI color codes from child output
256
257
  svc.lastErrors.push(line.replace(/\x1b\[[0-9;]*m/g, '').trim());
257
258
  if (svc.lastErrors.length > 12)
258
259
  svc.lastErrors.shift();
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Active upstream health-checking — opt-in. Periodically probes every known
3
+ * upstream URL and tracks healthy/unhealthy per endpoint, so the gateway routes
4
+ * a pooled service AROUND dead endpoints (instead of only discovering death
5
+ * passively, one failed request at a time) and the /statusz rollup reflects true
6
+ * liveness even with zero traffic.
7
+ *
8
+ * Liveness, not readiness: a probe is "healthy" when the endpoint ANSWERS with
9
+ * status < 500 — so a service without the health path still reads up on a 404;
10
+ * only a 5xx or a connection failure/timeout is down. New endpoints start
11
+ * optimistically healthy, so a not-yet-probed endpoint is never black-holed.
12
+ *
13
+ * Fail-open by design (see providers-prod `pick`): only multi-endpoint POOLS are
14
+ * health-filtered, and even then the gateway falls back to an unhealthy endpoint
15
+ * rather than 503 if a whole pool looks down — a checker false-positive must
16
+ * never take a service fully offline.
17
+ */
18
+ export interface HealthCheckerOptions {
19
+ /** Probe path appended to each upstream URL. Default `/healthz`. */
20
+ path?: string;
21
+ /** Probe period (ms). Default 5000. */
22
+ intervalMs?: number;
23
+ /** Per-probe timeout (ms). Default 2000. */
24
+ timeoutMs?: number;
25
+ /** Consecutive failures before an endpoint is marked unhealthy. Default 2. */
26
+ unhealthyThreshold?: number;
27
+ /** Consecutive successes before a down endpoint is marked healthy again. Default 1. */
28
+ healthyThreshold?: number;
29
+ /** Injectable fetch (tests). Defaults to global fetch. */
30
+ fetchImpl?: typeof fetch;
31
+ /** Notified when an endpoint flips health. */
32
+ onChange?: (url: string, healthy: boolean) => void;
33
+ }
34
+ export interface EndpointHealth {
35
+ url: string;
36
+ healthy: boolean;
37
+ fails: number;
38
+ lastCheckedAt: number | null;
39
+ }
40
+ export interface HealthChecker {
41
+ /** Set the current URL set to monitor (called on every route rebuild). */
42
+ track(urls: string[]): void;
43
+ /** Current health (default true for an untracked / not-yet-probed URL). */
44
+ isHealthy(url: string): boolean;
45
+ /** Per-endpoint health for the status page. */
46
+ snapshot(): EndpointHealth[];
47
+ /** Probe every tracked URL once (used by start()'s loop and by tests). */
48
+ probeOnce(): Promise<void>;
49
+ start(): void;
50
+ stop(): void;
51
+ }
52
+ export declare function createHealthChecker(opts?: HealthCheckerOptions): HealthChecker;
53
+ //# sourceMappingURL=health-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-check.d.ts","sourceRoot":"","sources":["../../../../../libs/cluster/src/executors/gateway/health-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACpD;AAED,MAAM,WAAW,cAAc;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;AAE9G,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC5B,2EAA2E;IAC3E,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,+CAA+C;IAC/C,QAAQ,IAAI,cAAc,EAAE,CAAC;IAC7B,0EAA0E;IAC1E,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;CACd;AAID,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,oBAAyB,GAAG,aAAa,CAyClF"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createHealthChecker = createHealthChecker;
4
+ function createHealthChecker(opts = {}) {
5
+ const path = opts.path ?? '/healthz';
6
+ const intervalMs = opts.intervalMs ?? 5000;
7
+ const timeoutMs = opts.timeoutMs ?? 2000;
8
+ const downAt = Math.max(1, opts.unhealthyThreshold ?? 2);
9
+ const upAt = Math.max(1, opts.healthyThreshold ?? 1);
10
+ const doFetch = opts.fetchImpl ?? globalThis.fetch;
11
+ const state = new Map();
12
+ let timer;
13
+ const probeUrl = (url) => url.replace(/\/+$/, '') + (path.startsWith('/') ? path : '/' + path);
14
+ const probe = async (url) => {
15
+ const st = state.get(url);
16
+ if (!st)
17
+ return;
18
+ let ok = false;
19
+ const ctl = new AbortController();
20
+ const t = setTimeout(() => ctl.abort(), timeoutMs);
21
+ try {
22
+ const res = await doFetch(probeUrl(url), { method: 'GET', signal: ctl.signal, redirect: 'manual' });
23
+ ok = res.status < 500; // answered → up (even 404); only 5xx counts as down
24
+ }
25
+ catch { /* network error / timeout → unhealthy (ok stays false) */ }
26
+ finally {
27
+ clearTimeout(t);
28
+ }
29
+ st.lastCheckedAt = Date.now();
30
+ if (ok) {
31
+ st.oks += 1;
32
+ st.fails = 0;
33
+ if (!st.healthy && st.oks >= upAt) {
34
+ st.healthy = true;
35
+ opts.onChange?.(url, true);
36
+ }
37
+ }
38
+ else {
39
+ st.fails += 1;
40
+ st.oks = 0;
41
+ if (st.healthy && st.fails >= downAt) {
42
+ st.healthy = false;
43
+ opts.onChange?.(url, false);
44
+ }
45
+ }
46
+ };
47
+ const probeOnce = () => Promise.allSettled([...state.keys()].map(probe)).then(() => undefined);
48
+ return {
49
+ track(urls) {
50
+ const next = new Set(urls);
51
+ for (const u of urls)
52
+ if (!state.has(u))
53
+ state.set(u, { healthy: true, fails: 0, oks: 0, lastCheckedAt: null });
54
+ for (const u of [...state.keys()])
55
+ if (!next.has(u))
56
+ state.delete(u);
57
+ },
58
+ isHealthy: (url) => state.get(url)?.healthy ?? true,
59
+ snapshot: () => [...state.entries()].map(([url, s]) => ({ url, healthy: s.healthy, fails: s.fails, lastCheckedAt: s.lastCheckedAt })),
60
+ probeOnce,
61
+ start() { if (timer)
62
+ return; timer = setInterval(() => void probeOnce(), intervalMs); timer.unref?.(); void probeOnce(); },
63
+ stop() { if (timer)
64
+ clearInterval(timer); timer = undefined; },
65
+ };
66
+ }
@@ -18,8 +18,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  * LENSMCP_GW_KEYS path to a {service: x-internal-token} JSON (the trust registry)
19
19
  * LENSMCP_GW_TLS_KEY path to TLS private key PEM (enables https)
20
20
  * LENSMCP_GW_TLS_CERT path to TLS cert PEM
21
- * LENSMCP_GW_JWT_REQUIRED "1" → jwt-mode routes require an `Authorization: Bearer …`
22
- * (minimal edge guard; swap in a full JWKS validator here)
21
+ * jwt routes ALWAYS require auth: validated against the verifier (JWKS/HS256) when
22
+ * configured, else FAIL CLOSED (401). LENSMCP_GW_JWT_PRESENCE_ONLY=1 opts into a
23
+ * weak bearer-presence-only edge guard when no verifier is wired (not recommended).
23
24
  * LENSMCP_EVENT_FILE set → enable the lens bus (OPT-IN; off by default)
24
25
  *
25
26
  * Targeted rollout (attribute-based routing; docs/design/targeted-rollout.md):
@@ -35,14 +36,68 @@ Object.defineProperty(exports, "__esModule", { value: true });
35
36
  * LENSMCP_GW_COOKIE_DOMAIN cookie Domain (e.g. ".tetros.ai" to span subdomains)
36
37
  * LENSMCP_GW_COOKIE_MAXAGE cookie Max-Age seconds (default 31536000)
37
38
  *
39
+ * Edge tuning (all optional — lib defaults are production-shaped):
40
+ * PORT platform-injected bind port (used when LENSMCP_GW_PORTS is unset)
41
+ * LENSMCP_GW_ACCESS_LOG "1" → one Cloud-Logging-shaped JSON line per request to stdout
42
+ * LENSMCP_GW_UPSTREAM_TLS_VERIFY "1" → verify upstream TLS certs (set for east-west on GCP;
43
+ * default off keeps local-CA / self-signed upstreams working)
44
+ * LENSMCP_GW_UPSTREAM_H2 "1" → HTTP/2 to upstreams (multiplex many MCP streams; Cloud Run speaks h2).
45
+ * Auto-on when mTLS is configured; set "0" to force h1.1.
46
+ * mTLS to upstreams (optional client cert; rides on h2). Server validation is the
47
+ * LENSMCP_GW_UPSTREAM_TLS_VERIFY toggle above ("option to not validate" = leave it off):
48
+ * LENSMCP_GW_MTLS_FROM_REDIS "1" → load cert/key/ca from shared Redis keys
49
+ * <prefix>:mtls:{cert,key,ca} (rotate by writing Redis; rolling-restart to apply)
50
+ * LENSMCP_GW_MTLS_CERT / _KEY / _CA PEM file paths (used when not loading from Redis)
51
+ * LENSMCP_GW_CLIENT_IP_HEADER header with the authoritative client IP from the front
52
+ * proxy (set `cf-connecting-ip` behind Cloudflare; feeds IP-based ABAC)
53
+ * LENSMCP_GW_CLIENT_IP_TRUSTED_PROXIES csv of CIDRs allowed to set that header
54
+ * (default loopback only — prevents off-proxy IP spoofing)
55
+ * LENSMCP_GW_UNDICI_CONNECTIONS per-origin connection pool size (default 256)
56
+ * LENSMCP_GW_UNDICI_BODY_TIMEOUT_MS undici response-body timeout; default 0 = unlimited
57
+ * (keeps long-lived SSE / streaming MCP responses open)
58
+ * LENSMCP_GW_KEEPALIVE_MS server keep-alive timeout; default 620000, kept ABOVE the GCP
59
+ * external ALB's 600s backend keep-alive (avoids intermittent 502s)
60
+ * LENSMCP_GW_REQUEST_TIMEOUT_MS inbound request timeout; default 0 = disabled (streaming)
61
+ *
62
+ * Distributed tracing (OpenTelemetry — on only when the OTLP endpoint is set):
63
+ * OTEL_EXPORTER_OTLP_ENDPOINT OTLP/HTTP endpoint (Cloud Trace / Collector / X-Ray / Tempo / Jaeger).
64
+ * Set → gateway emits a SERVER span per request + propagates W3C traceparent downstream.
65
+ * OTEL_SERVICE_NAME resource service.name (default "lensmcp-gateway")
66
+ * OTEL_EXPORTER_OTLP_HEADERS exporter auth headers (standard OTLP env, read by the exporter)
67
+ * LENSMCP_GW_OTEL_SAMPLE head sample ratio 0..1 for root spans (default 1)
68
+ *
69
+ * Status rollup (for a status page — observed health, not the routing registry):
70
+ * LENSMCP_GW_STATUS "1" → expose GET /statusz + (with Redis) fan health to status:<svc>:<instance>
71
+ * LENSMCP_GW_STATUS_TOKEN if set, /statusz (and /metricsz) require ?token= or x-status-token to match
72
+ * LENSMCP_GW_METRICS "1" → expose token-gated /metricsz (event-loop lag / rss / cpu / req rates) for load tests
73
+ *
74
+ * Active health-checking (probe upstreams; route pools around dead endpoints):
75
+ * LENSMCP_GW_HEALTH_CHECK "1" → probe every upstream and steer pooled picks to healthy ones
76
+ * LENSMCP_GW_HEALTH_PATH probe path (default /healthz); healthy = answers with status < 500
77
+ * LENSMCP_GW_HEALTH_INTERVAL_MS / LENSMCP_GW_HEALTH_TIMEOUT_MS probe period / timeout
78
+ *
79
+ * Rate limit (opt-in, per client IP; defense-in-depth behind the edge throttle):
80
+ * LENSMCP_GW_RATE_LIMIT requests allowed per window (enables the limiter)
81
+ * LENSMCP_GW_RATE_WINDOW_MS window the limit refills over (default 60000)
82
+ * LENSMCP_GW_RATE_LIMIT_REDIS "1" → ONE GLOBAL budget across all containers via the
83
+ * shared registry Redis (atomic Lua token-bucket); else per-instance
84
+ * LENSMCP_GW_RATE_LIMIT_REDIS_URL dedicated Redis for the limiter (else reuse the registry one)
85
+ * LENSMCP_GW_RATE_LIMIT_TIMEOUT_MS per-request Redis budget before the fail policy (default 100)
86
+ * LENSMCP_GW_RATE_LIMIT_FAIL_CLOSED "1" → deny on a Redis error/timeout (default: fail OPEN)
87
+ *
38
88
  * Manifests + endpoints + keys are FILE-backed here; a registry-backed
39
89
  * ManifestProvider (Redis/ConfigMap) drops in behind the same interface.
40
90
  */
41
91
  const node_fs_1 = require("node:fs");
42
92
  const node_crypto_1 = require("node:crypto");
43
93
  const node_path_1 = require("node:path");
94
+ const node_os_1 = require("node:os");
44
95
  const prod_gateway_lib_1 = require("./prod-gateway.lib");
45
96
  const jwks_verify_1 = require("./jwks-verify");
97
+ const otel_tracing_1 = require("./otel-tracing");
98
+ const health_check_1 = require("./health-check");
99
+ const rate_limit_1 = require("./rate-limit");
100
+ const metrics_1 = require("./metrics");
46
101
  const registry_source_1 = require("./registry-source");
47
102
  const providers_prod_1 = require("./providers-prod");
48
103
  function readJson(path, fallback) {
@@ -95,7 +150,9 @@ function watchJsonFile(path, onChange, pollMs = 1000) {
95
150
  }
96
151
  async function main() {
97
152
  const env = process.env;
98
- const ports = (env['LENSMCP_GW_PORTS'] ?? '').split(',').map((s) => Number(s.trim())).filter(Boolean);
153
+ // Bind ports: explicit LENSMCP_GW_PORTS wins; else honor the platform `PORT`
154
+ // contract (Cloud Run / buildpacks inject it); else the lib default (8080/8443).
155
+ const ports = (env['LENSMCP_GW_PORTS'] ?? env['PORT'] ?? '').split(',').map((s) => Number(s.trim())).filter(Boolean);
99
156
  // Process-level safety net: a single uncaught async error must not kill the
100
157
  // pod and 503 every in-flight request — log and keep serving.
101
158
  process.on('uncaughtException', (err) => console.error('[gateway] uncaughtException:', err));
@@ -108,10 +165,13 @@ async function main() {
108
165
  let pods;
109
166
  let stopEndpointsWatch;
110
167
  let registry;
168
+ // Reused (when present) for the status:* fan-out and shared mTLS material reads.
169
+ let redisClient;
111
170
  if (redisUrl) {
112
171
  // eslint-disable-next-line @typescript-eslint/no-require-imports
113
172
  const Redis = require('ioredis');
114
173
  const client = new Redis(redisUrl);
174
+ redisClient = client;
115
175
  const reg = (0, registry_source_1.createRegistryProviders)((0, registry_source_1.redisRegistrySource)(client, env['LENSMCP_GW_REDIS_PREFIX'] ? { prefix: env['LENSMCP_GW_REDIS_PREFIX'] } : {}), { onError: (e) => console.error('[gateway] registry:', e instanceof Error ? e.message : e) });
116
176
  await reg.start(); // warm the route table before serving
117
177
  manifests = reg.manifests;
@@ -160,10 +220,10 @@ async function main() {
160
220
  : undefined;
161
221
  // ── JWT verification: JWKS (RS256, prod) preferred, HS256 secret as fallback ──
162
222
  // One verifier powers BOTH identify() (claims → ABAC attributes) and the edge
163
- // authenticate() (reject jwt routes when LENSMCP_GW_JWT_REQUIRED). With neither
164
- // configured, jwt routes fall back to a bearer-presence check and identity
165
- // attributes are absent (IP/header/cookie rules still work).
166
- const jwtRequired = env['LENSMCP_GW_JWT_REQUIRED'] === '1';
223
+ // authenticate(). A `jwt` route with NO verifier configured FAILS CLOSED (401),
224
+ // unless LENSMCP_GW_JWT_PRESENCE_ONLY=1 explicitly opts into a weak bearer-presence
225
+ // edge guard (no signature check). Default is fail-closed, not pass-through.
226
+ const jwtPresenceOnly = env['LENSMCP_GW_JWT_PRESENCE_ONLY'] === '1';
167
227
  const jwksUrl = env['LENSMCP_GW_JWKS_URL'];
168
228
  const jwtSecret = env['LENSMCP_GW_JWT_SECRET'];
169
229
  const jwks = jwksUrl
@@ -202,13 +262,16 @@ async function main() {
202
262
  };
203
263
  const identify = (jwks || jwtSecret) ? bearerClaims : undefined;
204
264
  const authenticate = (mode, req) => {
205
- if (mode !== 'jwt' || !jwtRequired)
265
+ if (mode !== 'jwt')
206
266
  return;
207
267
  if (jwks || jwtSecret) {
208
268
  if (!bearerClaims(req))
209
269
  throw new Error('invalid or missing token');
210
270
  return;
211
271
  } // real verification
272
+ // No verifier configured → FAIL CLOSED, unless presence-only is explicitly opted in.
273
+ if (!jwtPresenceOnly)
274
+ throw new Error('jwt route but no verifier configured (set LENSMCP_GW_JWKS_URL or LENSMCP_GW_JWT_SECRET)');
212
275
  if (!String(req.headers['authorization'] ?? '').startsWith('Bearer '))
213
276
  throw new Error('missing bearer token');
214
277
  };
@@ -248,6 +311,133 @@ async function main() {
248
311
  console.error('[gateway] initial JWKS load failed (will retry in background):', e.message);
249
312
  }
250
313
  }
314
+ // ── edge tuning (all optional; sensible prod defaults live in the lib) ──
315
+ const accessLog = env['LENSMCP_GW_ACCESS_LOG'] === '1';
316
+ const clientIpHeader = env['LENSMCP_GW_CLIENT_IP_HEADER']; // e.g. cf-connecting-ip behind Cloudflare
317
+ // CIDRs of trusted front proxies that may set the client-IP header (default: loopback only).
318
+ const clientIpTrustedProxies = (env['LENSMCP_GW_CLIENT_IP_TRUSTED_PROXIES'] ?? '').split(',').map((s) => s.trim()).filter(Boolean);
319
+ const undici = {};
320
+ if (env['LENSMCP_GW_UPSTREAM_TLS_VERIFY'] === '1')
321
+ undici.rejectUnauthorized = true; // "option to not validate" = leave unset
322
+ if (env['LENSMCP_GW_UPSTREAM_H2'] === '1')
323
+ undici.allowH2 = true;
324
+ if (env['LENSMCP_GW_UNDICI_CONNECTIONS'])
325
+ undici.connections = Number(env['LENSMCP_GW_UNDICI_CONNECTIONS']);
326
+ if (env['LENSMCP_GW_UNDICI_BODY_TIMEOUT_MS'])
327
+ undici.bodyTimeout = Number(env['LENSMCP_GW_UNDICI_BODY_TIMEOUT_MS']);
328
+ // ── mTLS client materials (optional): from the shared registry Redis, or files ──
329
+ if (env['LENSMCP_GW_MTLS_FROM_REDIS'] === '1' && redisClient) {
330
+ const p = env['LENSMCP_GW_REDIS_PREFIX'] ?? 'lensmcp:gw';
331
+ const [cert, key, ca] = await redisClient.mget(`${p}:mtls:cert`, `${p}:mtls:key`, `${p}:mtls:ca`);
332
+ if (cert)
333
+ undici.cert = cert;
334
+ if (key)
335
+ undici.key = key;
336
+ if (ca)
337
+ undici.ca = ca;
338
+ if (cert || key)
339
+ console.log('[gateway] mTLS materials loaded from Redis');
340
+ }
341
+ else {
342
+ if (env['LENSMCP_GW_MTLS_CERT'])
343
+ undici.cert = (0, node_fs_1.readFileSync)(env['LENSMCP_GW_MTLS_CERT']);
344
+ if (env['LENSMCP_GW_MTLS_KEY'])
345
+ undici.key = (0, node_fs_1.readFileSync)(env['LENSMCP_GW_MTLS_KEY']);
346
+ if (env['LENSMCP_GW_MTLS_CA'])
347
+ undici.ca = (0, node_fs_1.readFileSync)(env['LENSMCP_GW_MTLS_CA']);
348
+ }
349
+ // mTLS rides on HTTP/2 by default (unless explicitly disabled with LENSMCP_GW_UPSTREAM_H2=0).
350
+ if (undici.cert && undici.key) {
351
+ if (env['LENSMCP_GW_UPSTREAM_H2'] !== '0')
352
+ undici.allowH2 = true;
353
+ console.log(`[gateway] mTLS to upstreams ON over ${undici.allowH2 ? 'h2' : 'h1.1'} (server validation ${undici.rejectUnauthorized ? 'enabled' : 'OFF'})`);
354
+ }
355
+ const server = {};
356
+ if (env['LENSMCP_GW_KEEPALIVE_MS'])
357
+ server.keepAliveTimeout = Number(env['LENSMCP_GW_KEEPALIVE_MS']);
358
+ if (env['LENSMCP_GW_REQUEST_TIMEOUT_MS'])
359
+ server.requestTimeout = Number(env['LENSMCP_GW_REQUEST_TIMEOUT_MS']);
360
+ // OTel distributed tracing — on only when OTEL_EXPORTER_OTLP_ENDPOINT is set.
361
+ const tracing = (0, otel_tracing_1.setupTracing)({
362
+ ...(env['OTEL_SERVICE_NAME'] ? { serviceName: env['OTEL_SERVICE_NAME'] } : {}),
363
+ ...(env['LENSMCP_GW_OTEL_SAMPLE'] ? { sampleRatio: Number(env['LENSMCP_GW_OTEL_SAMPLE']) } : {}),
364
+ });
365
+ if (tracing)
366
+ console.log(`[gateway] OTLP tracing on → ${env['OTEL_EXPORTER_OTLP_ENDPOINT']}`);
367
+ // Status rollup: /statusz endpoint (token-guarded) + a per-instance Redis
368
+ // `status:<service>:<host>` fan-out (TTL'd) that a status page reads with a
369
+ // read-only ACL scoped to `status:*` — never the routing control-plane keys.
370
+ const statusEnabled = env['LENSMCP_GW_STATUS'] === '1';
371
+ const statusToken = env['LENSMCP_GW_STATUS_TOKEN'];
372
+ const instance = (0, node_os_1.hostname)();
373
+ const statusTtl = Math.max(3, Math.ceil((Number(env['LENSMCP_GW_TRAFFIC_FLUSH_MS'] ?? 5000) / 1000) * 3));
374
+ const statusRedis = redisClient;
375
+ const onStatus = (statusEnabled && statusRedis)
376
+ ? (snapshot) => {
377
+ for (const s of snapshot) {
378
+ void statusRedis.set(`status:${s.service}:${instance}`, JSON.stringify({ ...s, instance, at: Date.now() }), 'EX', statusTtl).catch(() => undefined);
379
+ }
380
+ }
381
+ : undefined;
382
+ if (statusEnabled && !statusToken)
383
+ console.warn('[gateway] LENSMCP_GW_STATUS=1 but no LENSMCP_GW_STATUS_TOKEN — /statusz stays DISABLED (404) until a token is set (fail-closed). The Redis status:* fan-out still runs.');
384
+ if (statusEnabled)
385
+ console.log(`[gateway] status on — /statusz${statusToken ? '' : ' (endpoint disabled: no token)'}${onStatus ? ' + Redis status:* fan-out' : ''}`);
386
+ // Active upstream health-checking — probes upstreams, routes pools around dead
387
+ // endpoints, and feeds true liveness into /statusz. Default off (passive only).
388
+ const healthChecker = env['LENSMCP_GW_HEALTH_CHECK'] === '1'
389
+ ? (0, health_check_1.createHealthChecker)({
390
+ ...(env['LENSMCP_GW_HEALTH_PATH'] ? { path: env['LENSMCP_GW_HEALTH_PATH'] } : {}),
391
+ ...(env['LENSMCP_GW_HEALTH_INTERVAL_MS'] ? { intervalMs: Number(env['LENSMCP_GW_HEALTH_INTERVAL_MS']) } : {}),
392
+ ...(env['LENSMCP_GW_HEALTH_TIMEOUT_MS'] ? { timeoutMs: Number(env['LENSMCP_GW_HEALTH_TIMEOUT_MS']) } : {}),
393
+ })
394
+ : undefined;
395
+ if (healthChecker)
396
+ console.log(`[gateway] active health-checking on (path ${env['LENSMCP_GW_HEALTH_PATH'] ?? '/healthz'})`);
397
+ // Per-client-IP rate limit (opt-in; defense-in-depth behind Cloudflare/Cloud Armor).
398
+ // LENSMCP_GW_RATE_LIMIT_REDIS=1 makes it ONE GLOBAL budget shared by every gateway
399
+ // container (atomic Lua token-bucket on the shared registry Redis — or a dedicated
400
+ // LENSMCP_GW_RATE_LIMIT_REDIS_URL); fail-open on a Redis blip. Otherwise it's the
401
+ // per-instance in-memory limiter (whose effective limit multiplies by container count).
402
+ let rateLimiter;
403
+ let rlRedisClient; // a dedicated client we own and must quit
404
+ if (env['LENSMCP_GW_RATE_LIMIT']) {
405
+ const limit = Number(env['LENSMCP_GW_RATE_LIMIT']);
406
+ const windowMs = Number(env['LENSMCP_GW_RATE_WINDOW_MS'] ?? 60_000);
407
+ const wantRedis = env['LENSMCP_GW_RATE_LIMIT_REDIS'] === '1' || !!env['LENSMCP_GW_RATE_LIMIT_REDIS_URL'];
408
+ if (wantRedis) {
409
+ const dedicatedUrl = env['LENSMCP_GW_RATE_LIMIT_REDIS_URL'];
410
+ let client;
411
+ if (dedicatedUrl) {
412
+ const Redis = require('ioredis');
413
+ rlRedisClient = new Redis(dedicatedUrl);
414
+ client = rlRedisClient;
415
+ }
416
+ else if (redisClient) {
417
+ client = redisClient; // reuse the registry Redis
418
+ }
419
+ if (client) {
420
+ const failClosed = env['LENSMCP_GW_RATE_LIMIT_FAIL_CLOSED'] === '1';
421
+ rateLimiter = (0, rate_limit_1.createRedisRateLimiter)(client, {
422
+ limit, windowMs,
423
+ ...(env['LENSMCP_GW_RATE_LIMIT_TIMEOUT_MS'] ? { timeoutMs: Number(env['LENSMCP_GW_RATE_LIMIT_TIMEOUT_MS']) } : {}),
424
+ ...(failClosed ? { failOpen: false } : {}),
425
+ });
426
+ console.log(`[gateway] rate limit on — ${limit} req / ${windowMs}ms GLOBAL (Redis: ${dedicatedUrl ? 'dedicated' : 'shared registry'}, fail-${failClosed ? 'closed' : 'open'}) per client IP`);
427
+ }
428
+ else {
429
+ console.warn('[gateway] LENSMCP_GW_RATE_LIMIT_REDIS set but no Redis configured (set LENSMCP_GW_REDIS_URL or LENSMCP_GW_RATE_LIMIT_REDIS_URL) — falling back to PER-INSTANCE in-memory limiting.');
430
+ }
431
+ }
432
+ if (!rateLimiter) {
433
+ rateLimiter = (0, rate_limit_1.createRateLimiter)({ limit, windowMs });
434
+ console.log(`[gateway] rate limit on — ${limit} req / ${windowMs}ms per client IP (in-memory, per-instance)`);
435
+ }
436
+ }
437
+ // Process self-metrics (event-loop lag / rss / cpu / req rates) for load tests + monitoring.
438
+ const metrics = env['LENSMCP_GW_METRICS'] === '1' ? (0, metrics_1.createProcessMetrics)() : undefined;
439
+ if (metrics)
440
+ console.log(`[gateway] process metrics on — /metricsz${statusToken ? ' (token-gated)' : ' (DISABLED: needs LENSMCP_GW_STATUS_TOKEN)'}`);
251
441
  const handle = await (0, prod_gateway_lib_1.startProdGateway)({
252
442
  ...(ports.length ? { ports } : {}),
253
443
  manifests,
@@ -261,6 +451,19 @@ async function main() {
261
451
  ...(trustProxyIp ? { trustProxyIp } : {}),
262
452
  ...(cookie ? { cookie } : {}),
263
453
  ...(uidHeader ? { uidHeader } : {}),
454
+ ...(accessLog ? { accessLog: true } : {}),
455
+ ...(clientIpHeader ? { clientIpHeader } : {}),
456
+ ...(clientIpTrustedProxies.length ? { clientIpTrustedProxies } : {}),
457
+ ...(tracing ? { tracing } : {}),
458
+ ...(statusEnabled ? { statusEndpoint: true } : {}),
459
+ ...(statusToken ? { statusToken } : {}),
460
+ ...(onStatus ? { onStatus } : {}),
461
+ ...(healthChecker ? { healthChecker } : {}),
462
+ ...(rateLimiter ? { rateLimiter } : {}),
463
+ ...(metrics ? { metrics } : {}),
464
+ ...(env['LENSMCP_GW_TRAFFIC_FLUSH_MS'] ? { trafficFlushMs: Number(env['LENSMCP_GW_TRAFFIC_FLUSH_MS']) } : {}),
465
+ ...(Object.keys(undici).length ? { undici } : {}),
466
+ ...(Object.keys(server).length ? { server } : {}),
264
467
  });
265
468
  console.log(`[gateway] production gateway up on ${handle.ports.join(', ')} (${handle.routes().length} routes${emit ? ', lens ON' : ''})`);
266
469
  const shutdown = async (sig) => {
@@ -277,11 +480,19 @@ async function main() {
277
480
  registry?.stop();
278
481
  }
279
482
  catch { /* ignore */ }
483
+ try {
484
+ await rlRedisClient?.quit();
485
+ }
486
+ catch { /* ignore */ } // the dedicated rate-limit client we created (handle.stop() stops the limiter itself)
280
487
  try {
281
488
  jwks?.stop();
282
489
  }
283
490
  catch { /* ignore */ }
284
491
  await handle.stop();
492
+ try {
493
+ await tracing?.shutdown();
494
+ }
495
+ catch { /* ignore */ } // flush buffered spans before exit
285
496
  process.exit(0);
286
497
  };
287
498
  for (const sig of ['SIGTERM', 'SIGINT'])
@@ -114,10 +114,15 @@ export interface ManifestProvider {
114
114
  /** Resolves a service to a concrete upstream, with optional scale-from-zero. */
115
115
  export interface PodProvider {
116
116
  /** Pick an upstream for this service. `opts.version` pins a rollout cohort
117
- * (sticky canary / debugging); otherwise traffic is split by cohort weight. */
117
+ * (sticky canary / debugging); otherwise traffic is split by cohort weight.
118
+ * `opts.isHealthy` (when given) steers a pooled pick toward healthy endpoints
119
+ * — fail-open: if a whole pool looks down it still returns one. */
118
120
  pick(service: string, opts?: {
119
121
  version?: string;
122
+ isHealthy?: (url: string) => boolean;
120
123
  }): Upstream | undefined;
124
+ /** All upstream URLs this provider could route to — for active health-checking. */
125
+ endpoints?(): string[];
121
126
  /** Bring a scaled-to-zero service up (dev). Prod returns true (always on). */
122
127
  ensureUp?(service: string): Promise<boolean>;
123
128
  /** Drop a dead upstream so the next pick avoids it (refused socket / 502). */
@@ -235,7 +240,7 @@ export declare function manifestFromClusterDecl(project: string, decl: {
235
240
  /** A flat, read-only attribute bag assembled per request: verified JWT claims,
236
241
  * `ip`, `header.<name>`, `device` (sticky key), `path`, `method`. */
237
242
  export type Attrs = Record<string, unknown>;
238
- export type RuleOp = 'eq' | 'ne' | 'in' | 'nin' | 'prefix' | 'suffix' | 'contains' | 'regex' | 'exists' | 'gt' | 'lt' | 'cidr';
243
+ export type RuleOp = 'eq' | 'ne' | 'in' | 'nin' | 'prefix' | 'suffix' | 'contains' | 'hastoken' | 'regex' | 'exists' | 'gt' | 'lt' | 'cidr';
239
244
  export interface Condition {
240
245
  attr: string;
241
246
  op: RuleOp;
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../../../libs/cluster/src/executors/gateway/manifest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../../../libs/cluster/src/executors/gateway/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,6EAA6E;AAC7E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;6BAE6B;AAC7B,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,CAAC;AAErD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AACD,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;CAC5B;AAED;qEACqE;AACrE,MAAM,WAAW,SAAS;IACxB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,uFAAuF;IACvF,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC9B,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;0EACsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;CAC1B;AAED;;oEAEoE;AACpE,MAAM,MAAM,QAAQ,GAAG,CAAC;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzF;;yBAEyB;AACzB,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,IAAI,IAAI,aAAa,EAAE,CAAC;IACxB,+EAA+E;IAC/E,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC9D;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B;;;wEAGoE;IACpE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;KAAE,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC/G,mFAAmF;IACnF,SAAS,CAAC,IAAI,MAAM,EAAE,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,8EAA8E;IAC9E,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IACjD;mEAC+D;IAC/D,cAAc,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAC/F;mFAC+E;IAC/E,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;CACxE;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,MAAM,CAa/E;AAED;kFACkF;AAClF,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAIlE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,EACrE,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,CAAC,GAAG,SAAS,CASf;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAGhG;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAK9F;AAED,wFAAwF;AACxF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAED;;;;;GAKG;AACH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAUtE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAatG;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,GAChB,YAAY,CAGd;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,GAAG,KAAK,EAAE,CAgC5E;AAED;;kEAEkE;AAClE,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,IAAI,CAAC,EAAE,UAAU,CAAC;CAC7F,GACA,aAAa,GAAG,SAAS,CAe3B;AAUD;sEACsE;AACtE,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5C,MAAM,MAAM,MAAM,GACd,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAC1B,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAChC,UAAU,GACV,OAAO,GAAG,QAAQ,GAClB,IAAI,GAAG,IAAI,GACX,MAAM,CAAC;AAEX,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE;AACxE,MAAM,WAAW,SAAS;IAAG,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,QAAQ,CAAA;CAAE;AACjF,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAE7C,0FAA0F;AAC1F,MAAM,WAAW,UAAU;IAAG,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AA6B9E,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAW3D;AAiCD,sFAAsF;AACtF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAW9D;AAED,mEAAmE;AACnE,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,SAAS,UAAU,EAAE,EAAE,KAAK,EAAE,KAAK,GACzC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAKhD;AAED,4EAA4E;AAC5E,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIvC;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAU9E"}
@@ -138,8 +138,11 @@ function authRuleFor(policy, path, method) {
138
138
  continue;
139
139
  if (o.methods && !o.methods.some((x) => x.toUpperCase() === m))
140
140
  continue;
141
- const rule = o.rule ?? (o.permission ? { attr: 'perms', op: 'contains', value: o.permission } : undefined);
142
- return { mode: o.mode, ...(rule ? { rule } : {}) };
141
+ const rule = o.rule ?? (o.permission ? { attr: 'perms', op: 'hastoken', value: o.permission } : undefined);
142
+ // An override that omits `mode` INHERITS the service default otherwise a
143
+ // permission-only override would resolve to mode=undefined and the gateway
144
+ // would skip the jwt branch entirely, silently NOT enforcing the permission.
145
+ return { mode: o.mode ?? policy?.default ?? 'jwt', ...(rule ? { rule } : {}) };
143
146
  }
144
147
  return { mode: policy?.default ?? 'jwt' };
145
148
  }
@@ -281,7 +284,13 @@ function evalCondition(c, attrs) {
281
284
  case 'nin': return !(Array.isArray(c.value) && c.value.some((x) => Array.isArray(v) ? v.some((vv) => eq(vv, x)) : eq(v, x)));
282
285
  case 'prefix': return str(v).startsWith(str(c.value));
283
286
  case 'suffix': return str(v).endsWith(str(c.value));
284
- case 'contains': return Array.isArray(v) ? v.some((vv) => eq(vv, c.value)) : str(v).includes(str(c.value));
287
+ case 'contains': return Array.isArray(v) ? v.some((vv) => eq(vv, c.value)) : str(v).includes(str(c.value)); // substring / array element (general op)
288
+ // EXACT token in a list — a `perms`/scope STRING is delimited, so "superadmin"/"billing,adminx"
289
+ // must NOT satisfy hastoken:"admin". This is what `permission` compiles to (authz, no substring bypass).
290
+ case 'hastoken': {
291
+ const cv = str(c.value);
292
+ return Array.isArray(v) ? v.some((vv) => eq(vv, c.value)) : str(v).split(/[\s,]+/).filter(Boolean).includes(cv);
293
+ }
285
294
  case 'regex': {
286
295
  const re = compileRe(str(c.value));
287
296
  return re ? re.test(str(v)) : false;
@@ -296,14 +305,18 @@ function evalCondition(c, attrs) {
296
305
  function evalRule(node, attrs) {
297
306
  if (!isGroup(node))
298
307
  return evalCondition(node, attrs);
299
- if (node.all && !node.all.every((n) => evalRule(n, attrs)))
300
- return false;
301
- if (node.any && !node.any.some((n) => evalRule(n, attrs)))
308
+ // Only MEANINGFUL clauses count — an empty all:[]/any:[]/not:{} must NOT vacuously admit (fail closed),
309
+ // while a real `not:{cond}`-only rule still grants when its veto passes.
310
+ const all = Array.isArray(node.all) && node.all.length ? node.all : undefined;
311
+ const any = Array.isArray(node.any) && node.any.length ? node.any : undefined;
312
+ const not = node.not && Object.keys(node.not).length ? node.not : undefined;
313
+ if (not && evalRule(not, attrs))
314
+ return false; // veto
315
+ if (all && !all.every((n) => evalRule(n, attrs)))
302
316
  return false;
303
- if (node.not && evalRule(node.not, attrs))
317
+ if (any && !any.some((n) => evalRule(n, attrs)))
304
318
  return false;
305
- // an empty group ({}) matches nothing meaningful treat as no-match
306
- return !!(node.all || node.any || node.not);
319
+ return !!(all || any || not); // grant only if ≥1 meaningful clause was present (and satisfied)
307
320
  }
308
321
  /** First matching rule's version (top-to-bottom), or undefined. */
309
322
  function pickTargetedVersion(rules, attrs) {
@@ -0,0 +1,37 @@
1
+ export interface MetricsSnapshot {
2
+ uptimeSec: number;
3
+ rssMB: number;
4
+ heapUsedMB: number;
5
+ heapTotalMB: number;
6
+ externalMB: number;
7
+ /** CPU consumed in the interval since the previous snapshot. `percent` is of one core (single-threaded gateway). */
8
+ cpu: {
9
+ userMs: number;
10
+ systemMs: number;
11
+ percent: number;
12
+ };
13
+ /** Event-loop delay over the interval (ms). p99/max are the latency-killers to watch. */
14
+ loopLagMs: {
15
+ mean: number;
16
+ p50: number;
17
+ p90: number;
18
+ p99: number;
19
+ max: number;
20
+ };
21
+ requests: {
22
+ total: number;
23
+ sinceLast: number;
24
+ perSec: number;
25
+ s2xx: number;
26
+ s4xx: number;
27
+ s5xx: number;
28
+ };
29
+ }
30
+ export interface ProcessMetrics {
31
+ recordRequest(status: number): void;
32
+ /** Read-and-reset: returns interval deltas and resets the CPU/req/loop-lag windows. */
33
+ snapshot(): MetricsSnapshot;
34
+ stop(): void;
35
+ }
36
+ export declare function createProcessMetrics(): ProcessMetrics;
37
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../../../../libs/cluster/src/executors/gateway/metrics.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAC3E,oHAAoH;IACpH,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,yFAAyF;IACzF,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAChF,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1G;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uFAAuF;IACvF,QAAQ,IAAI,eAAe,CAAC;IAC5B,IAAI,IAAI,IAAI,CAAC;CACd;AAKD,wBAAgB,oBAAoB,IAAI,cAAc,CAkCrD"}