@queno/agent-node 0.1.2

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.
Files changed (154) hide show
  1. package/README.md +421 -0
  2. package/dist/agent.d.ts +222 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +591 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/api-discovery/discovery-buffer.d.ts +27 -0
  7. package/dist/api-discovery/discovery-buffer.d.ts.map +1 -0
  8. package/dist/api-discovery/discovery-buffer.js +50 -0
  9. package/dist/api-discovery/discovery-buffer.js.map +1 -0
  10. package/dist/api-discovery/endpoint-observer.d.ts +25 -0
  11. package/dist/api-discovery/endpoint-observer.d.ts.map +1 -0
  12. package/dist/api-discovery/endpoint-observer.js +127 -0
  13. package/dist/api-discovery/endpoint-observer.js.map +1 -0
  14. package/dist/api-discovery/route-normalizer.d.ts +15 -0
  15. package/dist/api-discovery/route-normalizer.d.ts.map +1 -0
  16. package/dist/api-discovery/route-normalizer.js +34 -0
  17. package/dist/api-discovery/route-normalizer.js.map +1 -0
  18. package/dist/config.d.ts +100 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +101 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/db-hooks/correlate.d.ts +19 -0
  23. package/dist/db-hooks/correlate.d.ts.map +1 -0
  24. package/dist/db-hooks/correlate.js +45 -0
  25. package/dist/db-hooks/correlate.js.map +1 -0
  26. package/dist/db-hooks/instrument.d.ts +27 -0
  27. package/dist/db-hooks/instrument.d.ts.map +1 -0
  28. package/dist/db-hooks/instrument.js +194 -0
  29. package/dist/db-hooks/instrument.js.map +1 -0
  30. package/dist/detectors/base.d.ts +61 -0
  31. package/dist/detectors/base.d.ts.map +1 -0
  32. package/dist/detectors/base.js +57 -0
  33. package/dist/detectors/base.js.map +1 -0
  34. package/dist/detectors/bola.d.ts +60 -0
  35. package/dist/detectors/bola.d.ts.map +1 -0
  36. package/dist/detectors/bola.js +108 -0
  37. package/dist/detectors/bola.js.map +1 -0
  38. package/dist/detectors/command-injection.d.ts +22 -0
  39. package/dist/detectors/command-injection.d.ts.map +1 -0
  40. package/dist/detectors/command-injection.js +41 -0
  41. package/dist/detectors/command-injection.js.map +1 -0
  42. package/dist/detectors/custom-rule.d.ts +24 -0
  43. package/dist/detectors/custom-rule.d.ts.map +1 -0
  44. package/dist/detectors/custom-rule.js +65 -0
  45. package/dist/detectors/custom-rule.js.map +1 -0
  46. package/dist/detectors/index.d.ts +17 -0
  47. package/dist/detectors/index.d.ts.map +1 -0
  48. package/dist/detectors/index.js +31 -0
  49. package/dist/detectors/index.js.map +1 -0
  50. package/dist/detectors/nosql-injection.d.ts +23 -0
  51. package/dist/detectors/nosql-injection.d.ts.map +1 -0
  52. package/dist/detectors/nosql-injection.js +54 -0
  53. package/dist/detectors/nosql-injection.js.map +1 -0
  54. package/dist/detectors/path-traversal.d.ts +21 -0
  55. package/dist/detectors/path-traversal.d.ts.map +1 -0
  56. package/dist/detectors/path-traversal.js +54 -0
  57. package/dist/detectors/path-traversal.js.map +1 -0
  58. package/dist/detectors/prototype-pollution.d.ts +23 -0
  59. package/dist/detectors/prototype-pollution.d.ts.map +1 -0
  60. package/dist/detectors/prototype-pollution.js +50 -0
  61. package/dist/detectors/prototype-pollution.js.map +1 -0
  62. package/dist/detectors/sql-injection.d.ts +22 -0
  63. package/dist/detectors/sql-injection.d.ts.map +1 -0
  64. package/dist/detectors/sql-injection.js +42 -0
  65. package/dist/detectors/sql-injection.js.map +1 -0
  66. package/dist/detectors/ssrf.d.ts +26 -0
  67. package/dist/detectors/ssrf.d.ts.map +1 -0
  68. package/dist/detectors/ssrf.js +37 -0
  69. package/dist/detectors/ssrf.js.map +1 -0
  70. package/dist/detectors/suspicious-headers.d.ts +25 -0
  71. package/dist/detectors/suspicious-headers.d.ts.map +1 -0
  72. package/dist/detectors/suspicious-headers.js +87 -0
  73. package/dist/detectors/suspicious-headers.js.map +1 -0
  74. package/dist/detectors/template-injection.d.ts +27 -0
  75. package/dist/detectors/template-injection.d.ts.map +1 -0
  76. package/dist/detectors/template-injection.js +35 -0
  77. package/dist/detectors/template-injection.js.map +1 -0
  78. package/dist/detectors/xss.d.ts +22 -0
  79. package/dist/detectors/xss.d.ts.map +1 -0
  80. package/dist/detectors/xss.js +38 -0
  81. package/dist/detectors/xss.js.map +1 -0
  82. package/dist/index.d.ts +28 -0
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +24 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/integrations/express.d.ts +39 -0
  87. package/dist/integrations/express.d.ts.map +1 -0
  88. package/dist/integrations/express.js +62 -0
  89. package/dist/integrations/express.js.map +1 -0
  90. package/dist/integrations/fastify.d.ts +33 -0
  91. package/dist/integrations/fastify.d.ts.map +1 -0
  92. package/dist/integrations/fastify.js +63 -0
  93. package/dist/integrations/fastify.js.map +1 -0
  94. package/dist/integrations/nestjs.d.ts +40 -0
  95. package/dist/integrations/nestjs.d.ts.map +1 -0
  96. package/dist/integrations/nestjs.js +58 -0
  97. package/dist/integrations/nestjs.js.map +1 -0
  98. package/dist/policy/canonical.d.ts +23 -0
  99. package/dist/policy/canonical.d.ts.map +1 -0
  100. package/dist/policy/canonical.js +40 -0
  101. package/dist/policy/canonical.js.map +1 -0
  102. package/dist/policy/policy-manager.d.ts +43 -0
  103. package/dist/policy/policy-manager.d.ts.map +1 -0
  104. package/dist/policy/policy-manager.js +89 -0
  105. package/dist/policy/policy-manager.js.map +1 -0
  106. package/dist/policy/types.d.ts +70 -0
  107. package/dist/policy/types.d.ts.map +1 -0
  108. package/dist/policy/types.js +2 -0
  109. package/dist/policy/types.js.map +1 -0
  110. package/dist/policy/verify.d.ts +11 -0
  111. package/dist/policy/verify.d.ts.map +1 -0
  112. package/dist/policy/verify.js +61 -0
  113. package/dist/policy/verify.js.map +1 -0
  114. package/dist/redaction/audit-log.d.ts +40 -0
  115. package/dist/redaction/audit-log.d.ts.map +1 -0
  116. package/dist/redaction/audit-log.js +110 -0
  117. package/dist/redaction/audit-log.js.map +1 -0
  118. package/dist/redaction/engine.d.ts +50 -0
  119. package/dist/redaction/engine.d.ts.map +1 -0
  120. package/dist/redaction/engine.js +143 -0
  121. package/dist/redaction/engine.js.map +1 -0
  122. package/dist/redaction/patterns.d.ts +24 -0
  123. package/dist/redaction/patterns.d.ts.map +1 -0
  124. package/dist/redaction/patterns.js +142 -0
  125. package/dist/redaction/patterns.js.map +1 -0
  126. package/dist/runtime-context.d.ts +33 -0
  127. package/dist/runtime-context.d.ts.map +1 -0
  128. package/dist/runtime-context.js +46 -0
  129. package/dist/runtime-context.js.map +1 -0
  130. package/dist/self-protect.d.ts +34 -0
  131. package/dist/self-protect.d.ts.map +1 -0
  132. package/dist/self-protect.js +134 -0
  133. package/dist/self-protect.js.map +1 -0
  134. package/dist/transport/buffer.d.ts +52 -0
  135. package/dist/transport/buffer.d.ts.map +1 -0
  136. package/dist/transport/buffer.js +57 -0
  137. package/dist/transport/buffer.js.map +1 -0
  138. package/dist/transport/client.d.ts +77 -0
  139. package/dist/transport/client.d.ts.map +1 -0
  140. package/dist/transport/client.js +178 -0
  141. package/dist/transport/client.js.map +1 -0
  142. package/dist/transport/heartbeat.d.ts +86 -0
  143. package/dist/transport/heartbeat.d.ts.map +1 -0
  144. package/dist/transport/heartbeat.js +110 -0
  145. package/dist/transport/heartbeat.js.map +1 -0
  146. package/dist/transport/secure-request.d.ts +30 -0
  147. package/dist/transport/secure-request.d.ts.map +1 -0
  148. package/dist/transport/secure-request.js +95 -0
  149. package/dist/transport/secure-request.js.map +1 -0
  150. package/dist/types.d.ts +311 -0
  151. package/dist/types.d.ts.map +1 -0
  152. package/dist/types.js +12 -0
  153. package/dist/types.js.map +1 -0
  154. package/package.json +60 -0
package/dist/agent.js ADDED
@@ -0,0 +1,591 @@
1
+ /**
2
+ * {@link RaspAgent} - the entry point of the RASP runtime.
3
+ *
4
+ * Wires together five subsystems:
5
+ * 1. Detectors - pattern matchers run on every incoming request.
6
+ * 2. Redaction engine - strips secrets/PII before anything leaves the process.
7
+ * 3. Audit log - local JSONL trace of every redaction action.
8
+ * 4. Event buffer - batches sanitised events to the collector.
9
+ * 5. Heartbeat - liveness signal + kill-switch / policy delivery channel.
10
+ *
11
+ * Invariants enforced here:
12
+ * - {@link RaspAgent.inspect} never throws (fail-open).
13
+ * - A detection is **never** enqueued before passing through the redaction
14
+ * engine; if redaction fails the event is dropped and audit-logged.
15
+ * - When the kill switch is received, inspection is disabled and the buffer
16
+ * is drained.
17
+ */
18
+ import { validateConfig, COLLECTOR_URL } from "./config.js";
19
+ import { RedactionEngine } from "./redaction/engine.js";
20
+ import { AuditLog } from "./redaction/audit-log.js";
21
+ import { TransportClient } from "./transport/client.js";
22
+ import { EventBuffer } from "./transport/buffer.js";
23
+ import { HeartbeatScheduler } from "./transport/heartbeat.js";
24
+ import { createDefaultDetectors } from "./detectors/index.js";
25
+ import { CustomRuleDetector } from "./detectors/custom-rule.js";
26
+ import { extractPathId, extractJwtSub } from "./detectors/bola.js";
27
+ import { EndpointObserver } from "./api-discovery/endpoint-observer.js";
28
+ import { DiscoveryBuffer } from "./api-discovery/discovery-buffer.js";
29
+ import { PolicyManager } from "./policy/policy-manager.js";
30
+ import { instrumentDatabaseDrivers } from "./db-hooks/instrument.js";
31
+ import { correlateBola } from "./db-hooks/correlate.js";
32
+ import { startSelfProtection } from "./self-protect.js";
33
+ import { enterContext } from "./runtime-context.js";
34
+ export class RaspAgent {
35
+ /** Fully validated configuration with defaults applied. */
36
+ cfg;
37
+ redaction;
38
+ auditLog;
39
+ client;
40
+ buffer;
41
+ heartbeat;
42
+ /** Built-in signature detectors. */
43
+ baseDetectors;
44
+ /** User-supplied detectors passed to the constructor. */
45
+ extraDetectors;
46
+ /** Active detector chain, rebuilt when custom rules arrive via policy. */
47
+ detectors;
48
+ observer;
49
+ discoveryBuffer;
50
+ /** Verifies and tracks signed policies distributed by the control plane. */
51
+ policyManager;
52
+ /** Data residency directives applied in {@link handleDetection}. */
53
+ dataResidency = null;
54
+ /** Version the control plane wants this agent to run (canary cohort / pin). */
55
+ targetVersion = null;
56
+ /** True when an upgrade is available for this agent. */
57
+ upgradePending = false;
58
+ /** Set to true after a kill-switch heartbeat - short-circuits {@link inspect}. */
59
+ killed = false;
60
+ /** Stops the self-protection timer (Addendum E.7); null when disabled. */
61
+ stopSelfProtection = null;
62
+ /**
63
+ * Enforcement mode in effect. Initialised from `cfg.mode` and updated
64
+ * whenever the collector returns a different mode in a heartbeat response.
65
+ */
66
+ currentMode;
67
+ /**
68
+ * Deduplication key for `policy_rejected` telemetry: `"<version>:<reason>"`.
69
+ * Prevents spamming the collector on every heartbeat cycle when the same
70
+ * policy is repeatedly rejected (e.g. a persistent trust-anchor mismatch).
71
+ */
72
+ lastRejectedPolicyKey = null;
73
+ /**
74
+ * Build a new agent.
75
+ *
76
+ * The constructor validates the config (throws on bad input), instantiates
77
+ * the subsystems and registers the default detectors. The heartbeat loop is
78
+ * **not** started until {@link start} is called.
79
+ *
80
+ * @param rawConfig - User-supplied configuration. Validated via
81
+ * {@link validateConfig}; throws if required fields are missing.
82
+ * @param extraDetectors - Optional custom detectors appended after the
83
+ * built-in set. They run in declaration order and the first non-null
84
+ * detection wins.
85
+ */
86
+ constructor(rawConfig, extraDetectors = []) {
87
+ this.cfg = validateConfig(rawConfig);
88
+ this.currentMode = this.cfg.mode;
89
+ this.redaction = new RedactionEngine();
90
+ this.auditLog = this.cfg.auditLog
91
+ ? new AuditLog(this.cfg.auditLogPath, this.cfg.auditLogMaxBytes)
92
+ : null;
93
+ this.client = new TransportClient({
94
+ collectorUrl: COLLECTOR_URL,
95
+ apiKey: this.cfg.apiKey,
96
+ timeoutMs: this.cfg.transportTimeoutMs,
97
+ hmacSecret: this.cfg.hmacSecret,
98
+ tls: this.cfg.tls,
99
+ });
100
+ this.buffer = new EventBuffer(this.client, {
101
+ flushIntervalMs: this.cfg.flushIntervalMs,
102
+ maxSize: this.cfg.bufferMaxSize,
103
+ });
104
+ this.heartbeat = new HeartbeatScheduler(this.client, this.cfg, {
105
+ onKillSwitch: () => this.handleKillSwitch(),
106
+ onRecover: () => this.handleRecover(),
107
+ onPolicyChange: (version) => this.handlePolicyChange(version),
108
+ onModeChange: (mode) => {
109
+ // When a trust anchor is configured, mode changes must arrive through
110
+ // a verified signed policy (applyPolicy). The heartbeat mode field is
111
+ // an unsigned hint from the collector and must not bypass Ed25519
112
+ // verification - otherwise a compromised network path or collector
113
+ // could silently switch block → monitor (Addendum E.4.1).
114
+ //
115
+ // When no trust anchor is configured (e.g. legacy deployments that
116
+ // pre-date the signed-policy system) the heartbeat mode is the only
117
+ // available control channel, so we keep the original behaviour.
118
+ if (!this.policyManager.hasTrustAnchor) {
119
+ this.currentMode = mode;
120
+ }
121
+ },
122
+ onTargetVersion: (info) => this.handleTargetVersion(info),
123
+ getMode: () => this.currentMode,
124
+ });
125
+ this.baseDetectors = createDefaultDetectors();
126
+ this.extraDetectors = extraDetectors;
127
+ this.detectors = [...this.baseDetectors, ...this.extraDetectors];
128
+ this.policyManager = new PolicyManager(this.cfg.projectId, [this.cfg.policyPublicKey]);
129
+ this.observer = new EndpointObserver();
130
+ this.discoveryBuffer = new DiscoveryBuffer(this.client, this.observer, {
131
+ projectId: this.cfg.projectId,
132
+ agentId: this.cfg.agentId,
133
+ flushIntervalMs: this.cfg.discoveryFlushIntervalMs,
134
+ });
135
+ }
136
+ /**
137
+ * Start the heartbeat loop. Idempotent.
138
+ *
139
+ * Call once during application bootstrap, after the framework middleware
140
+ * has been registered. The buffer flush timer is already armed by the
141
+ * constructor.
142
+ */
143
+ start() {
144
+ if (this.cfg.instrumentDb) {
145
+ // Best-effort; never throws.
146
+ instrumentDatabaseDrivers();
147
+ }
148
+ if (this.cfg.selfProtect) {
149
+ this.stopSelfProtection = startSelfProtection({
150
+ checkHooks: this.cfg.instrumentDb,
151
+ antiDebug: true,
152
+ });
153
+ }
154
+ this.heartbeat.start();
155
+ }
156
+ /**
157
+ * Begin a request's runtime context for DB correlation. Called by the
158
+ * framework integration at the start of the request, before the handler runs,
159
+ * so DB queries issued during the request are attributed to it.
160
+ *
161
+ * @returns The bound context, or `null` when DB instrumentation is disabled.
162
+ */
163
+ beginRequest(req) {
164
+ if (!this.cfg.instrumentDb || this.killed)
165
+ return null;
166
+ const ctx = {
167
+ method: req.method,
168
+ path: req.path,
169
+ pathId: extractPathId(req.path),
170
+ userId: extractJwtSub(req.headers["authorization"]),
171
+ sourceIp: req.sourceIp,
172
+ authEnforced: false,
173
+ dbQueries: [],
174
+ };
175
+ try {
176
+ enterContext(ctx);
177
+ }
178
+ catch {
179
+ return null;
180
+ }
181
+ return ctx;
182
+ }
183
+ /**
184
+ * Finalise a request: record its outcome for traffic profiling and, when a
185
+ * DB context is present, run BOLA-via-DB correlation and report any finding.
186
+ */
187
+ endRequest(ctx, req, outcome) {
188
+ this.observeOutcome(req, outcome);
189
+ if (!ctx || this.killed)
190
+ return;
191
+ try {
192
+ if (outcome.authenticated) {
193
+ ctx.authEnforced = true;
194
+ if (!ctx.userId)
195
+ ctx.userId = "authenticated";
196
+ }
197
+ const detection = correlateBola(ctx);
198
+ if (detection)
199
+ this.handleDetection(detection, req).catch(() => { });
200
+ }
201
+ catch {
202
+ // Fail open.
203
+ }
204
+ }
205
+ /**
206
+ * The enforcement mode currently in effect. Reflects remote mode changes
207
+ * (heartbeat) and applied policies, so integrations should consult this
208
+ * rather than the boot config.
209
+ */
210
+ get mode() {
211
+ return this.currentMode;
212
+ }
213
+ /** The policy version currently applied (0 if none). */
214
+ get policyVersion() {
215
+ return this.policyManager.currentVersion;
216
+ }
217
+ /**
218
+ * Version the control plane wants this agent to run, and whether an upgrade
219
+ * is pending. The Node agent is delivered as an npm package and cannot
220
+ * hot-swap its own binary, so the upgrade is surfaced (logged + queryable)
221
+ * for the host's deployment automation to act on, rather than self-applied.
222
+ */
223
+ get desiredVersion() {
224
+ return { targetVersion: this.targetVersion, upgradePending: this.upgradePending };
225
+ }
226
+ /**
227
+ * React to the target version advertised by the heartbeat. Records the target
228
+ * and logs an actionable message when an upgrade is available. Never throws.
229
+ */
230
+ handleTargetVersion(info) {
231
+ this.targetVersion = info.targetVersion;
232
+ this.upgradePending =
233
+ info.upgradeAvailable &&
234
+ info.targetVersion != null &&
235
+ info.targetVersion !== this.cfg.agentVersion;
236
+ if (this.upgradePending) {
237
+ const parts = [`[rasp] upgrade available: ${this.cfg.agentVersion ?? "?"} -> ${info.targetVersion}`];
238
+ if (info.impact)
239
+ parts.push(`impact: ${info.impact}`);
240
+ if (info.changelog)
241
+ parts.push(`changelog: ${info.changelog}`);
242
+ try {
243
+ console.info(parts.join(" | "));
244
+ }
245
+ catch {
246
+ // Ignore logging failures.
247
+ }
248
+ }
249
+ }
250
+ /**
251
+ * Graceful shutdown.
252
+ *
253
+ * Stops the heartbeat timer, drains the buffer (final flush) and closes
254
+ * the audit log file descriptor. Safe to await during process exit.
255
+ */
256
+ async stop() {
257
+ this.heartbeat.stop();
258
+ this.stopSelfProtection?.();
259
+ await this.buffer.stop();
260
+ await this.discoveryBuffer.stop();
261
+ this.auditLog?.close();
262
+ }
263
+ /**
264
+ * Run every detector against a normalised request.
265
+ *
266
+ * Detectors run in registration order; the first one returning a non-null
267
+ * result wins. Detector exceptions are swallowed so that a bug in one
268
+ * detector cannot take down the host application.
269
+ *
270
+ * @param req - Framework-agnostic request view.
271
+ * @returns The first {@link DetectionResult} found, or `null` when the
272
+ * request is clean (or when the kill switch is active).
273
+ *
274
+ * @remarks Side-effects (redaction, audit log, buffering) happen in the
275
+ * background via {@link handleDetection}; this method itself returns
276
+ * synchronously.
277
+ */
278
+ /**
279
+ * Record the response-phase outcome of a request for API-discovery traffic
280
+ * profiling (status code, latency, confirmed auth middleware execution).
281
+ * Called by the framework integration's response hook. Never throws.
282
+ */
283
+ observeOutcome(req, outcome) {
284
+ if (this.killed)
285
+ return;
286
+ try {
287
+ this.observer.observeOutcome(req, outcome);
288
+ }
289
+ catch {
290
+ // Fail open.
291
+ }
292
+ }
293
+ inspect(req) {
294
+ if (this.killed)
295
+ return null;
296
+ // Observe passively before running detectors - fail open
297
+ this.observer.observe(req);
298
+ for (const detector of this.detectors) {
299
+ let result = null;
300
+ try {
301
+ result = detector.detect(req);
302
+ }
303
+ catch {
304
+ continue;
305
+ }
306
+ if (result) {
307
+ this.handleDetection(result, req).catch(() => { });
308
+ return result;
309
+ }
310
+ }
311
+ return null;
312
+ }
313
+ /**
314
+ * Build a raw event payload, redact it, audit-log locally and enqueue it.
315
+ *
316
+ * Control flow:
317
+ * 1. Assemble the raw {@link EventPayload} from config + detection + request.
318
+ * 2. Run it through the {@link RedactionEngine}. On failure → drop and
319
+ * audit-log with `dropped: true`.
320
+ * 3. If any field was redacted → write a non-dropped audit-log line.
321
+ * 4. Stamp `auditLoggedLocally` into the event metadata and enqueue.
322
+ */
323
+ async handleDetection(detection, req) {
324
+ const raw = {
325
+ projectId: this.cfg.projectId,
326
+ agentId: this.cfg.agentId,
327
+ agentVersion: this.cfg.agentVersion,
328
+ runtime: this.cfg.runtime,
329
+ framework: this.cfg.framework,
330
+ eventType: detection.eventType,
331
+ severity: detection.severity,
332
+ action: this.currentMode,
333
+ method: req.method,
334
+ path: req.path,
335
+ sourceIp: req.sourceIp,
336
+ timestamp: new Date().toISOString(),
337
+ metadata: {
338
+ redacted: true,
339
+ matchedRule: detection.detectorName,
340
+ detectorDescription: detection.description,
341
+ location: detection.location,
342
+ matchedValue: detection.matchedValue,
343
+ },
344
+ };
345
+ let redacted;
346
+ let redactedFields;
347
+ try {
348
+ const result = this.redaction.redact(raw);
349
+ redacted = result.redacted;
350
+ redactedFields = result.redactedFields;
351
+ }
352
+ catch (err) {
353
+ this.auditLog?.write({
354
+ ts: new Date().toISOString(),
355
+ agentId: this.cfg.agentId,
356
+ projectId: this.cfg.projectId,
357
+ eventType: detection.eventType,
358
+ redactedFields: [],
359
+ dropped: true,
360
+ dropReason: err instanceof Error ? err.message : "redaction_failed",
361
+ });
362
+ return;
363
+ }
364
+ const auditLoggedLocally = redactedFields.length > 0;
365
+ this.auditLog?.write({
366
+ ts: new Date().toISOString(),
367
+ agentId: this.cfg.agentId,
368
+ projectId: this.cfg.projectId,
369
+ eventType: detection.eventType,
370
+ severity: detection.severity,
371
+ detectorName: detection.detectorName,
372
+ redactedFields,
373
+ dropped: false,
374
+ });
375
+ const event = redacted;
376
+ event.metadata["auditLoggedLocally"] = auditLoggedLocally;
377
+ const forSend = this.applyDataResidency(event);
378
+ if (forSend) {
379
+ this.buffer.enqueue(forSend);
380
+ }
381
+ }
382
+ /**
383
+ * Apply data residency directives (Addendum B.3) before an event is queued
384
+ * for transmission.
385
+ *
386
+ * @returns The (possibly trimmed) event to send, or `null` if the event must
387
+ * stay local / be skipped. The local audit log has already been written by
388
+ * the caller, so dropping here still leaves a verifiable local record.
389
+ */
390
+ applyDataResidency(event) {
391
+ const dr = this.dataResidency;
392
+ if (!dr)
393
+ return event;
394
+ // Local-only: nothing leaves the customer environment.
395
+ if (dr.localOnly)
396
+ return null;
397
+ // Selective export by event type.
398
+ if (dr.exportEventTypes && dr.exportEventTypes.length > 0) {
399
+ if (!dr.exportEventTypes.includes(event.eventType))
400
+ return null;
401
+ }
402
+ // Selective export: blocked detections only.
403
+ if (dr.exportBlockedOnly && event.action !== "block")
404
+ return null;
405
+ // Metadata-only: strip everything but the minimal envelope + flags.
406
+ if (dr.metadataOnly) {
407
+ return {
408
+ ...event,
409
+ metadata: {
410
+ redacted: true,
411
+ matchedRule: event.metadata.matchedRule,
412
+ auditLoggedLocally: event.metadata.auditLoggedLocally,
413
+ },
414
+ };
415
+ }
416
+ return event;
417
+ }
418
+ /**
419
+ * Handle a kill-switch heartbeat response.
420
+ *
421
+ * Disables inspection, drains the buffer and closes the audit log. The
422
+ * heartbeat scheduler has already stopped itself by the time this is
423
+ * called.
424
+ */
425
+ handleKillSwitch() {
426
+ this.killed = true;
427
+ this.stopSelfProtection?.();
428
+ this.stopSelfProtection = null;
429
+ // Buffers and audit log are kept open so they can resume if the kill
430
+ // switch is lifted. Only agent.stop() (graceful shutdown) closes them.
431
+ }
432
+ /**
433
+ * Called when the kill switch transitions from active back to inactive.
434
+ * Re-enables inspection and restarts self-protection if configured.
435
+ */
436
+ handleRecover() {
437
+ this.killed = false;
438
+ if (this.cfg.selfProtect && !this.stopSelfProtection) {
439
+ this.stopSelfProtection = startSelfProtection({
440
+ checkHooks: this.cfg.instrumentDb,
441
+ antiDebug: true,
442
+ });
443
+ }
444
+ }
445
+ /**
446
+ * React to a policy-version change signalled by the heartbeat.
447
+ *
448
+ * Fetches the latest signed policy, verifies its Ed25519 signature against
449
+ * the pinned trust anchor, and applies it. An untrusted, malformed or stale
450
+ * policy is ignored and the agent keeps its current configuration
451
+ * (self-rollback of policy - Addendum D.4 / E.4.1). Never throws.
452
+ *
453
+ * Rejections are surfaced via a `console.warn` and a `policy_rejected`
454
+ * telemetry event so operators can diagnose trust-anchor mismatches without
455
+ * reading raw application logs.
456
+ */
457
+ handlePolicyChange(version) {
458
+ void version;
459
+ if (this.killed)
460
+ return;
461
+ if (!this.policyManager.hasTrustAnchor) {
462
+ try {
463
+ console.warn("[rasp] policy update ignored: no trust anchor configured");
464
+ }
465
+ catch {
466
+ // Ignore logging failures.
467
+ }
468
+ return;
469
+ }
470
+ this.client
471
+ .fetchPolicy(this.cfg.agentId, this.cfg.channel)
472
+ .then((policy) => {
473
+ if (!policy)
474
+ return;
475
+ const result = this.policyManager.accept(policy);
476
+ if (result.applied) {
477
+ try {
478
+ this.applyPolicy(policy);
479
+ }
480
+ catch {
481
+ // Self-rollback: applying the new policy failed - restore the
482
+ // previous one so the agent keeps a known-good configuration.
483
+ const restored = this.policyManager.rollback();
484
+ if (restored) {
485
+ try {
486
+ this.applyPolicy(restored);
487
+ }
488
+ catch {
489
+ // Give up safely; existing in-memory config remains.
490
+ }
491
+ }
492
+ }
493
+ }
494
+ else {
495
+ try {
496
+ console.warn(`[rasp] policy v${policy.version} rejected: ${result.reason}` +
497
+ (policy.signingKeyId ? ` (keyId: ${policy.signingKeyId})` : ""));
498
+ }
499
+ catch {
500
+ // Ignore logging failures.
501
+ }
502
+ this.enqueuePolicyRejected(policy.version, result.reason ?? "unknown", policy.signingKeyId);
503
+ }
504
+ })
505
+ .catch(() => {
506
+ // Fail-safe: keep the current policy on any error.
507
+ });
508
+ }
509
+ /**
510
+ * Emit a single `policy_rejected` telemetry event so the control plane can
511
+ * surface trust-anchor or signature mismatches in the dashboard.
512
+ *
513
+ * The event is deduplicated by `version:reason` so a persistent rejection
514
+ * (e.g. a misconfigured trust anchor that the operator has not yet fixed)
515
+ * does not flood the collector on every heartbeat cycle.
516
+ *
517
+ * The payload passes through the redaction engine (Addendum B.2 / AGENTS.md
518
+ * rule: "All telemetry must pass through the redaction engine before
519
+ * buffering") and the data-residency filter before being enqueued.
520
+ */
521
+ enqueuePolicyRejected(version, reason, signingKeyId) {
522
+ const key = `${version}:${reason}`;
523
+ if (key === this.lastRejectedPolicyKey)
524
+ return;
525
+ this.lastRejectedPolicyKey = key;
526
+ const raw = {
527
+ projectId: this.cfg.projectId,
528
+ agentId: this.cfg.agentId,
529
+ agentVersion: this.cfg.agentVersion,
530
+ runtime: this.cfg.runtime,
531
+ framework: this.cfg.framework,
532
+ eventType: "policy_rejected",
533
+ severity: "low",
534
+ action: this.currentMode,
535
+ timestamp: new Date().toISOString(),
536
+ metadata: {
537
+ redacted: true,
538
+ version,
539
+ reason,
540
+ ...(signingKeyId ? { signingKeyId } : {}),
541
+ },
542
+ };
543
+ let event;
544
+ try {
545
+ event = this.redaction.redact(raw).redacted;
546
+ }
547
+ catch {
548
+ return;
549
+ }
550
+ const forSend = this.applyDataResidency(event);
551
+ if (forSend) {
552
+ this.buffer.enqueue(forSend);
553
+ }
554
+ }
555
+ /**
556
+ * Apply a verified policy to the live agent: enforcement mode, customer
557
+ * detection rules, redaction configuration and data residency directives.
558
+ */
559
+ applyPolicy(policy) {
560
+ // Mode
561
+ if (policy.mode === "monitor" || policy.mode === "block") {
562
+ this.currentMode = policy.mode;
563
+ }
564
+ // Custom detection rules → rebuild the detector chain.
565
+ this.rebuildDetectors(policy.detectionRules ?? []);
566
+ // Redaction configuration.
567
+ this.applyRedactionConfig(policy.redactionConfig);
568
+ // Data residency directives.
569
+ this.dataResidency = policy.dataResidency ?? null;
570
+ }
571
+ /** Rebuild the active detector chain from base + custom rules + extras. */
572
+ rebuildDetectors(rules) {
573
+ const next = [...this.baseDetectors];
574
+ if (rules.length > 0) {
575
+ const custom = new CustomRuleDetector(rules);
576
+ if (custom.size > 0)
577
+ next.push(custom);
578
+ }
579
+ next.push(...this.extraDetectors);
580
+ this.detectors = next;
581
+ }
582
+ /**
583
+ * Reconfigure the redaction engine from a policy. The engine always keeps its
584
+ * built-in protections; the policy can only add field-name patterns and tune
585
+ * value-based redaction / IP handling.
586
+ */
587
+ applyRedactionConfig(cfg) {
588
+ this.redaction = RedactionEngine.fromConfig(cfg ?? undefined);
589
+ }
590
+ }
591
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Periodic buffer that drains {@link EndpointObserver} and ships batches to
3
+ * the collector via {@link TransportClient.sendDiscovery}.
4
+ *
5
+ * - Flushes every `flushIntervalMs` milliseconds (default 60 s).
6
+ * - Sends at most 500 endpoints per HTTP call; splits into multiple calls if needed.
7
+ * - Fail-open: transport errors are swallowed so the host application is not affected.
8
+ */
9
+ import type { TransportClient } from "../transport/client.js";
10
+ import type { EndpointObserver } from "./endpoint-observer.js";
11
+ export interface DiscoveryBufferOptions {
12
+ projectId: string;
13
+ agentId: string;
14
+ flushIntervalMs: number;
15
+ }
16
+ export declare class DiscoveryBuffer {
17
+ private readonly client;
18
+ private readonly observer;
19
+ private readonly projectId;
20
+ private readonly agentId;
21
+ private timer;
22
+ constructor(client: TransportClient, observer: EndpointObserver, opts: DiscoveryBufferOptions);
23
+ /** Stop the flush timer and send a final batch. */
24
+ stop(): Promise<void>;
25
+ private flush;
26
+ }
27
+ //# sourceMappingURL=discovery-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery-buffer.d.ts","sourceRoot":"","sources":["../../src/api-discovery/discovery-buffer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB;AAID,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,KAAK,CAA+C;gBAG1D,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,sBAAsB;IAe9B,mDAAmD;IAC7C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAQb,KAAK;CAqBpB"}