trusera-sdk 1.1.0 → 1.1.1

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/dist/index.cjs CHANGED
@@ -47,6 +47,7 @@ var TruseraClient = class {
47
47
  apiKey;
48
48
  baseUrl;
49
49
  batchSize;
50
+ maxQueueSize;
50
51
  flushInterval;
51
52
  debug;
52
53
  agentId;
@@ -66,6 +67,7 @@ var TruseraClient = class {
66
67
  this.baseUrl = options.baseUrl ?? "https://api.trusera.io";
67
68
  this.agentId = options.agentId;
68
69
  this.batchSize = options.batchSize ?? 100;
70
+ this.maxQueueSize = options.maxQueueSize ?? 1e4;
69
71
  this.flushInterval = options.flushInterval ?? 5e3;
70
72
  this.debug = options.debug ?? false;
71
73
  const envAuto = (typeof process !== "undefined" ? process.env?.TRUSERA_AUTO_REGISTER : void 0) ?? "";
@@ -111,7 +113,7 @@ var TruseraClient = class {
111
113
  name,
112
114
  framework,
113
115
  metadata: {
114
- sdk_version: "0.1.0",
116
+ sdk_version: SDK_VERSION,
115
117
  runtime: "node",
116
118
  node_version: process.version
117
119
  }
@@ -141,10 +143,14 @@ var TruseraClient = class {
141
143
  metadata: {
142
144
  ...event.metadata,
143
145
  agent_id: this.agentId,
144
- sdk_version: "0.1.0"
146
+ sdk_version: SDK_VERSION
145
147
  }
146
148
  };
147
149
  this.eventQueue.push(enrichedEvent);
150
+ while (this.eventQueue.length > this.maxQueueSize) {
151
+ this.eventQueue.shift();
152
+ this.log("Event queue overflow, dropping oldest event");
153
+ }
148
154
  this.log("Event tracked", { type: event.type, name: event.name, queueSize: this.eventQueue.length });
149
155
  if (this.eventQueue.length >= this.batchSize) {
150
156
  void this.flush();
@@ -214,7 +220,7 @@ var TruseraClient = class {
214
220
  if (typeof process === "undefined") return {};
215
221
  return {
216
222
  pid: process.pid,
217
- argv: process.argv?.slice(0, 10),
223
+ argv: process.argv?.slice(0, 2),
218
224
  node_version: process.version,
219
225
  platform: process.platform,
220
226
  arch: process.arch
@@ -362,13 +368,47 @@ function tryRequire(moduleName) {
362
368
  return null;
363
369
  }
364
370
  }
371
+ var SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
372
+ "authorization",
373
+ "cookie",
374
+ "set-cookie",
375
+ "x-api-key",
376
+ "x-n8n-api-key",
377
+ "proxy-authorization"
378
+ ]);
379
+ function redactHeaders(headers) {
380
+ const redacted = {};
381
+ for (const [key, value] of Object.entries(headers)) {
382
+ redacted[key] = SENSITIVE_HEADERS.has(key.toLowerCase()) ? "[REDACTED]" : value;
383
+ }
384
+ return redacted;
385
+ }
386
+ var MAX_PATTERN_LENGTH = 500;
387
+ var EVIL_REGEX_PATTERNS = /(\.\*){2,}|(\w\+){2,}|\(\[^[^\]]*\]\*\)\*|\(\.\+\)\+/;
388
+ function safeRegExp(pattern) {
389
+ if (pattern.length > MAX_PATTERN_LENGTH) {
390
+ console.warn(`[Trusera] Exclude pattern too long (${pattern.length} > ${MAX_PATTERN_LENGTH}), skipping`);
391
+ return null;
392
+ }
393
+ if (EVIL_REGEX_PATTERNS.test(pattern)) {
394
+ console.warn(`[Trusera] Potentially dangerous regex pattern detected, skipping: ${pattern.slice(0, 50)}`);
395
+ return null;
396
+ }
397
+ try {
398
+ return new RegExp(pattern);
399
+ } catch (e) {
400
+ console.warn(`[Trusera] Invalid regex pattern, skipping: ${pattern.slice(0, 50)}`);
401
+ return null;
402
+ }
403
+ }
365
404
  var TruseraInterceptor = class {
366
405
  client = null;
367
406
  options = {
368
407
  enforcement: "log",
369
408
  policyUrl: "",
370
409
  excludePatterns: [],
371
- debug: false
410
+ debug: false,
411
+ failClosed: false
372
412
  };
373
413
  excludeRegexes = [];
374
414
  isInstalled = false;
@@ -405,9 +445,10 @@ var TruseraInterceptor = class {
405
445
  enforcement: options.enforcement ?? "log",
406
446
  policyUrl: options.policyUrl ?? "",
407
447
  excludePatterns: options.excludePatterns ?? [],
408
- debug: options.debug ?? false
448
+ debug: options.debug ?? false,
449
+ failClosed: options.failClosed ?? false
409
450
  };
410
- this.excludeRegexes = this.options.excludePatterns.map((pattern) => new RegExp(pattern));
451
+ this.excludeRegexes = this.options.excludePatterns.map((pattern) => safeRegExp(pattern)).filter((r) => r !== null);
411
452
  if (originalFetch === null) {
412
453
  originalFetch = globalThis.fetch;
413
454
  }
@@ -454,7 +495,7 @@ var TruseraInterceptor = class {
454
495
  const event = createEvent(
455
496
  "api_call" /* API_CALL */,
456
497
  eventName,
457
- { method, url, headers },
498
+ { method, url, headers: redactHeaders(headers) },
458
499
  { interception_mode: this.options.enforcement }
459
500
  );
460
501
  if (this.options.policyUrl) {
@@ -729,7 +770,7 @@ var TruseraInterceptor = class {
729
770
  response.headers.forEach((v, k) => {
730
771
  h[k] = v;
731
772
  });
732
- return h;
773
+ return redactHeaders(h);
733
774
  })()
734
775
  }
735
776
  );
@@ -774,7 +815,7 @@ var TruseraInterceptor = class {
774
815
  body = "[Binary data]";
775
816
  }
776
817
  }
777
- return { headers, body };
818
+ return { headers: redactHeaders(headers), body };
778
819
  }
779
820
  /**
780
821
  * Evaluates request against Cedar policies.
@@ -801,11 +842,21 @@ var TruseraInterceptor = class {
801
842
  });
802
843
  if (!response.ok) {
803
844
  console.error(`[Trusera] Policy evaluation failed: ${response.status}`);
845
+ if (this.options.failClosed && this.options.enforcement === "block") {
846
+ console.warn("[Trusera] FAIL-CLOSED: Policy service returned error, denying request");
847
+ return { decision: "Deny", reasons: [`Policy service error: ${response.status}`] };
848
+ }
849
+ console.warn("[Trusera] FAIL-OPEN: Policy service returned error, allowing request");
804
850
  return { decision: "Allow" };
805
851
  }
806
852
  return await response.json();
807
853
  } catch (error) {
808
854
  console.error("[Trusera] Policy evaluation error:", error);
855
+ if (this.options.failClosed && this.options.enforcement === "block") {
856
+ console.warn("[Trusera] FAIL-CLOSED: Policy evaluation failed, denying request");
857
+ return { decision: "Deny", reasons: ["Policy evaluation failed (fail-closed mode)"] };
858
+ }
859
+ console.warn("[Trusera] FAIL-OPEN: Policy evaluation failed, allowing request");
809
860
  return { decision: "Allow" };
810
861
  }
811
862
  }
@@ -1010,6 +1061,24 @@ var CedarEvaluator = class {
1010
1061
  };
1011
1062
 
1012
1063
  // src/standalone.ts
1064
+ var MAX_PATTERN_LENGTH2 = 500;
1065
+ var EVIL_REGEX_PATTERNS2 = /(\.\*){2,}|(\w\+){2,}|\(\[^[^\]]*\]\*\)\*|\(\.\+\)\+/;
1066
+ function safeRegExp2(pattern) {
1067
+ if (pattern.length > MAX_PATTERN_LENGTH2) {
1068
+ console.warn(`[Trusera Standalone] Exclude pattern too long, skipping`);
1069
+ return null;
1070
+ }
1071
+ if (EVIL_REGEX_PATTERNS2.test(pattern)) {
1072
+ console.warn(`[Trusera Standalone] Potentially dangerous regex pattern, skipping`);
1073
+ return null;
1074
+ }
1075
+ try {
1076
+ return new RegExp(pattern);
1077
+ } catch {
1078
+ console.warn(`[Trusera Standalone] Invalid regex pattern, skipping`);
1079
+ return null;
1080
+ }
1081
+ }
1013
1082
  var activeStandaloneInterceptor = null;
1014
1083
  var originalFetch2 = null;
1015
1084
  var StandaloneInterceptor = class {
@@ -1026,9 +1095,7 @@ var StandaloneInterceptor = class {
1026
1095
  excludePatterns: options.excludePatterns ?? [],
1027
1096
  debug: options.debug ?? false
1028
1097
  };
1029
- this.excludeRegexes = this.options.excludePatterns.map(
1030
- (pattern) => new RegExp(pattern)
1031
- );
1098
+ this.excludeRegexes = this.options.excludePatterns.map((pattern) => safeRegExp2(pattern)).filter((r) => r !== null);
1032
1099
  }
1033
1100
  /**
1034
1101
  * Installs the standalone interceptor.