palaryn 0.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.
Files changed (607) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +716 -0
  3. package/dist/sdk/typescript/src/client.d.ts +71 -0
  4. package/dist/sdk/typescript/src/client.d.ts.map +1 -0
  5. package/dist/sdk/typescript/src/client.js +176 -0
  6. package/dist/sdk/typescript/src/client.js.map +1 -0
  7. package/dist/sdk/typescript/src/errors.d.ts +50 -0
  8. package/dist/sdk/typescript/src/errors.d.ts.map +1 -0
  9. package/dist/sdk/typescript/src/errors.js +103 -0
  10. package/dist/sdk/typescript/src/errors.js.map +1 -0
  11. package/dist/sdk/typescript/src/index.d.ts +4 -0
  12. package/dist/sdk/typescript/src/index.d.ts.map +1 -0
  13. package/dist/sdk/typescript/src/index.js +15 -0
  14. package/dist/sdk/typescript/src/index.js.map +1 -0
  15. package/dist/sdk/typescript/src/types.d.ts +101 -0
  16. package/dist/sdk/typescript/src/types.d.ts.map +1 -0
  17. package/dist/sdk/typescript/src/types.js +6 -0
  18. package/dist/sdk/typescript/src/types.js.map +1 -0
  19. package/dist/src/admin/index.d.ts +2 -0
  20. package/dist/src/admin/index.d.ts.map +1 -0
  21. package/dist/src/admin/index.js +6 -0
  22. package/dist/src/admin/index.js.map +1 -0
  23. package/dist/src/admin/routes.d.ts +5 -0
  24. package/dist/src/admin/routes.d.ts.map +1 -0
  25. package/dist/src/admin/routes.js +471 -0
  26. package/dist/src/admin/routes.js.map +1 -0
  27. package/dist/src/admin/templates.d.ts +51 -0
  28. package/dist/src/admin/templates.d.ts.map +1 -0
  29. package/dist/src/admin/templates.js +500 -0
  30. package/dist/src/admin/templates.js.map +1 -0
  31. package/dist/src/anomaly/detector.d.ts +141 -0
  32. package/dist/src/anomaly/detector.d.ts.map +1 -0
  33. package/dist/src/anomaly/detector.js +554 -0
  34. package/dist/src/anomaly/detector.js.map +1 -0
  35. package/dist/src/anomaly/index.d.ts +2 -0
  36. package/dist/src/anomaly/index.d.ts.map +1 -0
  37. package/dist/src/anomaly/index.js +7 -0
  38. package/dist/src/anomaly/index.js.map +1 -0
  39. package/dist/src/approval/manager.d.ts +147 -0
  40. package/dist/src/approval/manager.d.ts.map +1 -0
  41. package/dist/src/approval/manager.js +511 -0
  42. package/dist/src/approval/manager.js.map +1 -0
  43. package/dist/src/approval/webhook.d.ts +36 -0
  44. package/dist/src/approval/webhook.d.ts.map +1 -0
  45. package/dist/src/approval/webhook.js +135 -0
  46. package/dist/src/approval/webhook.js.map +1 -0
  47. package/dist/src/audit/logger.d.ts +70 -0
  48. package/dist/src/audit/logger.d.ts.map +1 -0
  49. package/dist/src/audit/logger.js +440 -0
  50. package/dist/src/audit/logger.js.map +1 -0
  51. package/dist/src/auth/index.d.ts +6 -0
  52. package/dist/src/auth/index.d.ts.map +1 -0
  53. package/dist/src/auth/index.js +22 -0
  54. package/dist/src/auth/index.js.map +1 -0
  55. package/dist/src/auth/password.d.ts +3 -0
  56. package/dist/src/auth/password.d.ts.map +1 -0
  57. package/dist/src/auth/password.js +25 -0
  58. package/dist/src/auth/password.js.map +1 -0
  59. package/dist/src/auth/pkce.d.ts +13 -0
  60. package/dist/src/auth/pkce.d.ts.map +1 -0
  61. package/dist/src/auth/pkce.js +58 -0
  62. package/dist/src/auth/pkce.js.map +1 -0
  63. package/dist/src/auth/providers.d.ts +28 -0
  64. package/dist/src/auth/providers.d.ts.map +1 -0
  65. package/dist/src/auth/providers.js +198 -0
  66. package/dist/src/auth/providers.js.map +1 -0
  67. package/dist/src/auth/routes.d.ts +14 -0
  68. package/dist/src/auth/routes.d.ts.map +1 -0
  69. package/dist/src/auth/routes.js +431 -0
  70. package/dist/src/auth/routes.js.map +1 -0
  71. package/dist/src/auth/session.d.ts +24 -0
  72. package/dist/src/auth/session.d.ts.map +1 -0
  73. package/dist/src/auth/session.js +105 -0
  74. package/dist/src/auth/session.js.map +1 -0
  75. package/dist/src/billing/index.d.ts +7 -0
  76. package/dist/src/billing/index.d.ts.map +1 -0
  77. package/dist/src/billing/index.js +14 -0
  78. package/dist/src/billing/index.js.map +1 -0
  79. package/dist/src/billing/plan-enforcer.d.ts +44 -0
  80. package/dist/src/billing/plan-enforcer.d.ts.map +1 -0
  81. package/dist/src/billing/plan-enforcer.js +110 -0
  82. package/dist/src/billing/plan-enforcer.js.map +1 -0
  83. package/dist/src/billing/routes.d.ts +15 -0
  84. package/dist/src/billing/routes.d.ts.map +1 -0
  85. package/dist/src/billing/routes.js +193 -0
  86. package/dist/src/billing/routes.js.map +1 -0
  87. package/dist/src/billing/stripe-client.d.ts +14 -0
  88. package/dist/src/billing/stripe-client.d.ts.map +1 -0
  89. package/dist/src/billing/stripe-client.js +51 -0
  90. package/dist/src/billing/stripe-client.js.map +1 -0
  91. package/dist/src/billing/webhook-handler.d.ts +19 -0
  92. package/dist/src/billing/webhook-handler.d.ts.map +1 -0
  93. package/dist/src/billing/webhook-handler.js +169 -0
  94. package/dist/src/billing/webhook-handler.js.map +1 -0
  95. package/dist/src/billing/webhook-routes.d.ts +5 -0
  96. package/dist/src/billing/webhook-routes.d.ts.map +1 -0
  97. package/dist/src/billing/webhook-routes.js +30 -0
  98. package/dist/src/billing/webhook-routes.js.map +1 -0
  99. package/dist/src/budget/manager.d.ts +95 -0
  100. package/dist/src/budget/manager.d.ts.map +1 -0
  101. package/dist/src/budget/manager.js +547 -0
  102. package/dist/src/budget/manager.js.map +1 -0
  103. package/dist/src/budget/usage-extractor.d.ts +38 -0
  104. package/dist/src/budget/usage-extractor.d.ts.map +1 -0
  105. package/dist/src/budget/usage-extractor.js +165 -0
  106. package/dist/src/budget/usage-extractor.js.map +1 -0
  107. package/dist/src/cli.d.ts +3 -0
  108. package/dist/src/cli.d.ts.map +1 -0
  109. package/dist/src/cli.js +115 -0
  110. package/dist/src/cli.js.map +1 -0
  111. package/dist/src/config/defaults.d.ts +3 -0
  112. package/dist/src/config/defaults.d.ts.map +1 -0
  113. package/dist/src/config/defaults.js +243 -0
  114. package/dist/src/config/defaults.js.map +1 -0
  115. package/dist/src/config/validate.d.ts +15 -0
  116. package/dist/src/config/validate.d.ts.map +1 -0
  117. package/dist/src/config/validate.js +105 -0
  118. package/dist/src/config/validate.js.map +1 -0
  119. package/dist/src/dlp/composite-scanner.d.ts +47 -0
  120. package/dist/src/dlp/composite-scanner.d.ts.map +1 -0
  121. package/dist/src/dlp/composite-scanner.js +186 -0
  122. package/dist/src/dlp/composite-scanner.js.map +1 -0
  123. package/dist/src/dlp/index.d.ts +10 -0
  124. package/dist/src/dlp/index.d.ts.map +1 -0
  125. package/dist/src/dlp/index.js +26 -0
  126. package/dist/src/dlp/index.js.map +1 -0
  127. package/dist/src/dlp/interfaces.d.ts +33 -0
  128. package/dist/src/dlp/interfaces.d.ts.map +1 -0
  129. package/dist/src/dlp/interfaces.js +3 -0
  130. package/dist/src/dlp/interfaces.js.map +1 -0
  131. package/dist/src/dlp/patterns.d.ts +9 -0
  132. package/dist/src/dlp/patterns.d.ts.map +1 -0
  133. package/dist/src/dlp/patterns.js +25 -0
  134. package/dist/src/dlp/patterns.js.map +1 -0
  135. package/dist/src/dlp/prompt-injection-backend.d.ts +68 -0
  136. package/dist/src/dlp/prompt-injection-backend.d.ts.map +1 -0
  137. package/dist/src/dlp/prompt-injection-backend.js +148 -0
  138. package/dist/src/dlp/prompt-injection-backend.js.map +1 -0
  139. package/dist/src/dlp/prompt-injection-patterns.d.ts +32 -0
  140. package/dist/src/dlp/prompt-injection-patterns.d.ts.map +1 -0
  141. package/dist/src/dlp/prompt-injection-patterns.js +290 -0
  142. package/dist/src/dlp/prompt-injection-patterns.js.map +1 -0
  143. package/dist/src/dlp/regex-backend.d.ts +32 -0
  144. package/dist/src/dlp/regex-backend.d.ts.map +1 -0
  145. package/dist/src/dlp/regex-backend.js +153 -0
  146. package/dist/src/dlp/regex-backend.js.map +1 -0
  147. package/dist/src/dlp/scanner.d.ts +122 -0
  148. package/dist/src/dlp/scanner.d.ts.map +1 -0
  149. package/dist/src/dlp/scanner.js +444 -0
  150. package/dist/src/dlp/scanner.js.map +1 -0
  151. package/dist/src/dlp/text-normalizer.d.ts +41 -0
  152. package/dist/src/dlp/text-normalizer.d.ts.map +1 -0
  153. package/dist/src/dlp/text-normalizer.js +203 -0
  154. package/dist/src/dlp/text-normalizer.js.map +1 -0
  155. package/dist/src/dlp/trufflehog-backend.d.ts +64 -0
  156. package/dist/src/dlp/trufflehog-backend.d.ts.map +1 -0
  157. package/dist/src/dlp/trufflehog-backend.js +151 -0
  158. package/dist/src/dlp/trufflehog-backend.js.map +1 -0
  159. package/dist/src/executor/http-executor.d.ts +25 -0
  160. package/dist/src/executor/http-executor.d.ts.map +1 -0
  161. package/dist/src/executor/http-executor.js +333 -0
  162. package/dist/src/executor/http-executor.js.map +1 -0
  163. package/dist/src/executor/index.d.ts +6 -0
  164. package/dist/src/executor/index.d.ts.map +1 -0
  165. package/dist/src/executor/index.js +12 -0
  166. package/dist/src/executor/index.js.map +1 -0
  167. package/dist/src/executor/interfaces.d.ts +11 -0
  168. package/dist/src/executor/interfaces.d.ts.map +1 -0
  169. package/dist/src/executor/interfaces.js +3 -0
  170. package/dist/src/executor/interfaces.js.map +1 -0
  171. package/dist/src/executor/noop-executor.d.ts +13 -0
  172. package/dist/src/executor/noop-executor.d.ts.map +1 -0
  173. package/dist/src/executor/noop-executor.js +21 -0
  174. package/dist/src/executor/noop-executor.js.map +1 -0
  175. package/dist/src/executor/registry.d.ts +30 -0
  176. package/dist/src/executor/registry.d.ts.map +1 -0
  177. package/dist/src/executor/registry.js +62 -0
  178. package/dist/src/executor/registry.js.map +1 -0
  179. package/dist/src/executor/slack-executor.d.ts +24 -0
  180. package/dist/src/executor/slack-executor.d.ts.map +1 -0
  181. package/dist/src/executor/slack-executor.js +147 -0
  182. package/dist/src/executor/slack-executor.js.map +1 -0
  183. package/dist/src/index.d.ts +25 -0
  184. package/dist/src/index.d.ts.map +1 -0
  185. package/dist/src/index.js +74 -0
  186. package/dist/src/index.js.map +1 -0
  187. package/dist/src/mcp/auth-verifier.d.ts +23 -0
  188. package/dist/src/mcp/auth-verifier.d.ts.map +1 -0
  189. package/dist/src/mcp/auth-verifier.js +162 -0
  190. package/dist/src/mcp/auth-verifier.js.map +1 -0
  191. package/dist/src/mcp/bridge.d.ts +132 -0
  192. package/dist/src/mcp/bridge.d.ts.map +1 -0
  193. package/dist/src/mcp/bridge.js +734 -0
  194. package/dist/src/mcp/bridge.js.map +1 -0
  195. package/dist/src/mcp/http-transport.d.ts +32 -0
  196. package/dist/src/mcp/http-transport.d.ts.map +1 -0
  197. package/dist/src/mcp/http-transport.js +538 -0
  198. package/dist/src/mcp/http-transport.js.map +1 -0
  199. package/dist/src/mcp/index.d.ts +10 -0
  200. package/dist/src/mcp/index.d.ts.map +1 -0
  201. package/dist/src/mcp/index.js +17 -0
  202. package/dist/src/mcp/index.js.map +1 -0
  203. package/dist/src/mcp/oauth-pages.d.ts +23 -0
  204. package/dist/src/mcp/oauth-pages.d.ts.map +1 -0
  205. package/dist/src/mcp/oauth-pages.js +121 -0
  206. package/dist/src/mcp/oauth-pages.js.map +1 -0
  207. package/dist/src/mcp/oauth-postgres-stores.d.ts +55 -0
  208. package/dist/src/mcp/oauth-postgres-stores.d.ts.map +1 -0
  209. package/dist/src/mcp/oauth-postgres-stores.js +226 -0
  210. package/dist/src/mcp/oauth-postgres-stores.js.map +1 -0
  211. package/dist/src/mcp/oauth-provider.d.ts +95 -0
  212. package/dist/src/mcp/oauth-provider.d.ts.map +1 -0
  213. package/dist/src/mcp/oauth-provider.js +360 -0
  214. package/dist/src/mcp/oauth-provider.js.map +1 -0
  215. package/dist/src/mcp/oauth-stores.d.ts +62 -0
  216. package/dist/src/mcp/oauth-stores.d.ts.map +1 -0
  217. package/dist/src/mcp/oauth-stores.js +154 -0
  218. package/dist/src/mcp/oauth-stores.js.map +1 -0
  219. package/dist/src/mcp/server.d.ts +18 -0
  220. package/dist/src/mcp/server.d.ts.map +1 -0
  221. package/dist/src/mcp/server.js +51 -0
  222. package/dist/src/mcp/server.js.map +1 -0
  223. package/dist/src/metrics/collector.d.ts +106 -0
  224. package/dist/src/metrics/collector.d.ts.map +1 -0
  225. package/dist/src/metrics/collector.js +311 -0
  226. package/dist/src/metrics/collector.js.map +1 -0
  227. package/dist/src/metrics/index.d.ts +2 -0
  228. package/dist/src/metrics/index.d.ts.map +1 -0
  229. package/dist/src/metrics/index.js +6 -0
  230. package/dist/src/metrics/index.js.map +1 -0
  231. package/dist/src/middleware/auth.d.ts +77 -0
  232. package/dist/src/middleware/auth.d.ts.map +1 -0
  233. package/dist/src/middleware/auth.js +720 -0
  234. package/dist/src/middleware/auth.js.map +1 -0
  235. package/dist/src/middleware/session.d.ts +18 -0
  236. package/dist/src/middleware/session.d.ts.map +1 -0
  237. package/dist/src/middleware/session.js +67 -0
  238. package/dist/src/middleware/session.js.map +1 -0
  239. package/dist/src/middleware/validate.d.ts +3 -0
  240. package/dist/src/middleware/validate.d.ts.map +1 -0
  241. package/dist/src/middleware/validate.js +85 -0
  242. package/dist/src/middleware/validate.js.map +1 -0
  243. package/dist/src/policy/engine.d.ts +107 -0
  244. package/dist/src/policy/engine.d.ts.map +1 -0
  245. package/dist/src/policy/engine.js +646 -0
  246. package/dist/src/policy/engine.js.map +1 -0
  247. package/dist/src/policy/index.d.ts +3 -0
  248. package/dist/src/policy/index.d.ts.map +1 -0
  249. package/dist/src/policy/index.js +8 -0
  250. package/dist/src/policy/index.js.map +1 -0
  251. package/dist/src/policy/opa-engine.d.ts +176 -0
  252. package/dist/src/policy/opa-engine.d.ts.map +1 -0
  253. package/dist/src/policy/opa-engine.js +790 -0
  254. package/dist/src/policy/opa-engine.js.map +1 -0
  255. package/dist/src/proxy/forward-proxy.d.ts +30 -0
  256. package/dist/src/proxy/forward-proxy.d.ts.map +1 -0
  257. package/dist/src/proxy/forward-proxy.js +580 -0
  258. package/dist/src/proxy/forward-proxy.js.map +1 -0
  259. package/dist/src/proxy/index.d.ts +2 -0
  260. package/dist/src/proxy/index.d.ts.map +1 -0
  261. package/dist/src/proxy/index.js +8 -0
  262. package/dist/src/proxy/index.js.map +1 -0
  263. package/dist/src/ratelimit/limiter.d.ts +45 -0
  264. package/dist/src/ratelimit/limiter.d.ts.map +1 -0
  265. package/dist/src/ratelimit/limiter.js +158 -0
  266. package/dist/src/ratelimit/limiter.js.map +1 -0
  267. package/dist/src/replay/engine.d.ts +40 -0
  268. package/dist/src/replay/engine.d.ts.map +1 -0
  269. package/dist/src/replay/engine.js +106 -0
  270. package/dist/src/replay/engine.js.map +1 -0
  271. package/dist/src/replay/index.d.ts +2 -0
  272. package/dist/src/replay/index.d.ts.map +1 -0
  273. package/dist/src/replay/index.js +6 -0
  274. package/dist/src/replay/index.js.map +1 -0
  275. package/dist/src/saas/index.d.ts +2 -0
  276. package/dist/src/saas/index.d.ts.map +1 -0
  277. package/dist/src/saas/index.js +18 -0
  278. package/dist/src/saas/index.js.map +1 -0
  279. package/dist/src/saas/routes.d.ts +18 -0
  280. package/dist/src/saas/routes.d.ts.map +1 -0
  281. package/dist/src/saas/routes.js +1566 -0
  282. package/dist/src/saas/routes.js.map +1 -0
  283. package/dist/src/server/app.d.ts +44 -0
  284. package/dist/src/server/app.d.ts.map +1 -0
  285. package/dist/src/server/app.js +854 -0
  286. package/dist/src/server/app.js.map +1 -0
  287. package/dist/src/server/errors.d.ts +32 -0
  288. package/dist/src/server/errors.d.ts.map +1 -0
  289. package/dist/src/server/errors.js +39 -0
  290. package/dist/src/server/errors.js.map +1 -0
  291. package/dist/src/server/gateway.d.ts +165 -0
  292. package/dist/src/server/gateway.d.ts.map +1 -0
  293. package/dist/src/server/gateway.js +964 -0
  294. package/dist/src/server/gateway.js.map +1 -0
  295. package/dist/src/server/index.d.ts +2 -0
  296. package/dist/src/server/index.d.ts.map +1 -0
  297. package/dist/src/server/index.js +295 -0
  298. package/dist/src/server/index.js.map +1 -0
  299. package/dist/src/server/logger.d.ts +33 -0
  300. package/dist/src/server/logger.d.ts.map +1 -0
  301. package/dist/src/server/logger.js +230 -0
  302. package/dist/src/server/logger.js.map +1 -0
  303. package/dist/src/server/stream-proxy.d.ts +32 -0
  304. package/dist/src/server/stream-proxy.d.ts.map +1 -0
  305. package/dist/src/server/stream-proxy.js +184 -0
  306. package/dist/src/server/stream-proxy.js.map +1 -0
  307. package/dist/src/storage/file-persistence.d.ts +48 -0
  308. package/dist/src/storage/file-persistence.d.ts.map +1 -0
  309. package/dist/src/storage/file-persistence.js +280 -0
  310. package/dist/src/storage/file-persistence.js.map +1 -0
  311. package/dist/src/storage/index.d.ts +5 -0
  312. package/dist/src/storage/index.d.ts.map +1 -0
  313. package/dist/src/storage/index.js +21 -0
  314. package/dist/src/storage/index.js.map +1 -0
  315. package/dist/src/storage/interfaces.d.ts +237 -0
  316. package/dist/src/storage/interfaces.d.ts.map +1 -0
  317. package/dist/src/storage/interfaces.js +3 -0
  318. package/dist/src/storage/interfaces.js.map +1 -0
  319. package/dist/src/storage/memory.d.ts +162 -0
  320. package/dist/src/storage/memory.d.ts.map +1 -0
  321. package/dist/src/storage/memory.js +603 -0
  322. package/dist/src/storage/memory.js.map +1 -0
  323. package/dist/src/storage/postgres.d.ts +267 -0
  324. package/dist/src/storage/postgres.d.ts.map +1 -0
  325. package/dist/src/storage/postgres.js +1555 -0
  326. package/dist/src/storage/postgres.js.map +1 -0
  327. package/dist/src/storage/redis.d.ts +202 -0
  328. package/dist/src/storage/redis.d.ts.map +1 -0
  329. package/dist/src/storage/redis.js +629 -0
  330. package/dist/src/storage/redis.js.map +1 -0
  331. package/dist/src/tracing/index.d.ts +2 -0
  332. package/dist/src/tracing/index.d.ts.map +1 -0
  333. package/dist/src/tracing/index.js +6 -0
  334. package/dist/src/tracing/index.js.map +1 -0
  335. package/dist/src/tracing/provider.d.ts +43 -0
  336. package/dist/src/tracing/provider.d.ts.map +1 -0
  337. package/dist/src/tracing/provider.js +74 -0
  338. package/dist/src/tracing/provider.js.map +1 -0
  339. package/dist/src/trust/calculator.d.ts +54 -0
  340. package/dist/src/trust/calculator.d.ts.map +1 -0
  341. package/dist/src/trust/calculator.js +102 -0
  342. package/dist/src/trust/calculator.js.map +1 -0
  343. package/dist/src/trust/index.d.ts +2 -0
  344. package/dist/src/trust/index.d.ts.map +1 -0
  345. package/dist/src/trust/index.js +7 -0
  346. package/dist/src/trust/index.js.map +1 -0
  347. package/dist/src/types/budget.d.ts +30 -0
  348. package/dist/src/types/budget.d.ts.map +1 -0
  349. package/dist/src/types/budget.js +3 -0
  350. package/dist/src/types/budget.js.map +1 -0
  351. package/dist/src/types/config.d.ts +176 -0
  352. package/dist/src/types/config.d.ts.map +1 -0
  353. package/dist/src/types/config.js +3 -0
  354. package/dist/src/types/config.js.map +1 -0
  355. package/dist/src/types/events.d.ts +24 -0
  356. package/dist/src/types/events.d.ts.map +1 -0
  357. package/dist/src/types/events.js +3 -0
  358. package/dist/src/types/events.js.map +1 -0
  359. package/dist/src/types/index.d.ts +8 -0
  360. package/dist/src/types/index.d.ts.map +1 -0
  361. package/dist/src/types/index.js +24 -0
  362. package/dist/src/types/index.js.map +1 -0
  363. package/dist/src/types/policy.d.ts +60 -0
  364. package/dist/src/types/policy.d.ts.map +1 -0
  365. package/dist/src/types/policy.js +3 -0
  366. package/dist/src/types/policy.js.map +1 -0
  367. package/dist/src/types/stripe-config.d.ts +12 -0
  368. package/dist/src/types/stripe-config.d.ts.map +1 -0
  369. package/dist/src/types/stripe-config.js +3 -0
  370. package/dist/src/types/stripe-config.js.map +1 -0
  371. package/dist/src/types/subscription.d.ts +24 -0
  372. package/dist/src/types/subscription.d.ts.map +1 -0
  373. package/dist/src/types/subscription.js +38 -0
  374. package/dist/src/types/subscription.js.map +1 -0
  375. package/dist/src/types/tool-call.d.ts +42 -0
  376. package/dist/src/types/tool-call.d.ts.map +1 -0
  377. package/dist/src/types/tool-call.js +3 -0
  378. package/dist/src/types/tool-call.js.map +1 -0
  379. package/dist/src/types/tool-result.d.ts +58 -0
  380. package/dist/src/types/tool-result.d.ts.map +1 -0
  381. package/dist/src/types/tool-result.js +3 -0
  382. package/dist/src/types/tool-result.js.map +1 -0
  383. package/dist/src/types/user.d.ts +101 -0
  384. package/dist/src/types/user.d.ts.map +1 -0
  385. package/dist/src/types/user.js +6 -0
  386. package/dist/src/types/user.js.map +1 -0
  387. package/dist/tests/integration/api.test.d.ts +2 -0
  388. package/dist/tests/integration/api.test.d.ts.map +1 -0
  389. package/dist/tests/integration/api.test.js +1199 -0
  390. package/dist/tests/integration/api.test.js.map +1 -0
  391. package/dist/tests/integration/proxy.test.d.ts +2 -0
  392. package/dist/tests/integration/proxy.test.d.ts.map +1 -0
  393. package/dist/tests/integration/proxy.test.js +251 -0
  394. package/dist/tests/integration/proxy.test.js.map +1 -0
  395. package/dist/tests/integration/storage.test.d.ts +16 -0
  396. package/dist/tests/integration/storage.test.d.ts.map +1 -0
  397. package/dist/tests/integration/storage.test.js +826 -0
  398. package/dist/tests/integration/storage.test.js.map +1 -0
  399. package/dist/tests/unit/admin.test.d.ts +2 -0
  400. package/dist/tests/unit/admin.test.d.ts.map +1 -0
  401. package/dist/tests/unit/admin.test.js +698 -0
  402. package/dist/tests/unit/admin.test.js.map +1 -0
  403. package/dist/tests/unit/anomaly-detector.test.d.ts +2 -0
  404. package/dist/tests/unit/anomaly-detector.test.d.ts.map +1 -0
  405. package/dist/tests/unit/anomaly-detector.test.js +903 -0
  406. package/dist/tests/unit/anomaly-detector.test.js.map +1 -0
  407. package/dist/tests/unit/approval-manager.test.d.ts +2 -0
  408. package/dist/tests/unit/approval-manager.test.d.ts.map +1 -0
  409. package/dist/tests/unit/approval-manager.test.js +528 -0
  410. package/dist/tests/unit/approval-manager.test.js.map +1 -0
  411. package/dist/tests/unit/approval-webhook.test.d.ts +2 -0
  412. package/dist/tests/unit/approval-webhook.test.d.ts.map +1 -0
  413. package/dist/tests/unit/approval-webhook.test.js +355 -0
  414. package/dist/tests/unit/approval-webhook.test.js.map +1 -0
  415. package/dist/tests/unit/audit-logger.test.d.ts +2 -0
  416. package/dist/tests/unit/audit-logger.test.d.ts.map +1 -0
  417. package/dist/tests/unit/audit-logger.test.js +635 -0
  418. package/dist/tests/unit/audit-logger.test.js.map +1 -0
  419. package/dist/tests/unit/auth-routes.test.d.ts +2 -0
  420. package/dist/tests/unit/auth-routes.test.d.ts.map +1 -0
  421. package/dist/tests/unit/auth-routes.test.js +281 -0
  422. package/dist/tests/unit/auth-routes.test.js.map +1 -0
  423. package/dist/tests/unit/auth.test.d.ts +2 -0
  424. package/dist/tests/unit/auth.test.d.ts.map +1 -0
  425. package/dist/tests/unit/auth.test.js +1382 -0
  426. package/dist/tests/unit/auth.test.js.map +1 -0
  427. package/dist/tests/unit/billing.test.d.ts +2 -0
  428. package/dist/tests/unit/billing.test.d.ts.map +1 -0
  429. package/dist/tests/unit/billing.test.js +579 -0
  430. package/dist/tests/unit/billing.test.js.map +1 -0
  431. package/dist/tests/unit/budget-manager.test.d.ts +2 -0
  432. package/dist/tests/unit/budget-manager.test.d.ts.map +1 -0
  433. package/dist/tests/unit/budget-manager.test.js +778 -0
  434. package/dist/tests/unit/budget-manager.test.js.map +1 -0
  435. package/dist/tests/unit/budget-race.test.d.ts +2 -0
  436. package/dist/tests/unit/budget-race.test.d.ts.map +1 -0
  437. package/dist/tests/unit/budget-race.test.js +58 -0
  438. package/dist/tests/unit/budget-race.test.js.map +1 -0
  439. package/dist/tests/unit/cli.test.d.ts +2 -0
  440. package/dist/tests/unit/cli.test.d.ts.map +1 -0
  441. package/dist/tests/unit/cli.test.js +93 -0
  442. package/dist/tests/unit/cli.test.js.map +1 -0
  443. package/dist/tests/unit/concurrency.test.d.ts +2 -0
  444. package/dist/tests/unit/concurrency.test.d.ts.map +1 -0
  445. package/dist/tests/unit/concurrency.test.js +1270 -0
  446. package/dist/tests/unit/concurrency.test.js.map +1 -0
  447. package/dist/tests/unit/config-validate.test.d.ts +2 -0
  448. package/dist/tests/unit/config-validate.test.d.ts.map +1 -0
  449. package/dist/tests/unit/config-validate.test.js +230 -0
  450. package/dist/tests/unit/config-validate.test.js.map +1 -0
  451. package/dist/tests/unit/defaults.test.d.ts +2 -0
  452. package/dist/tests/unit/defaults.test.d.ts.map +1 -0
  453. package/dist/tests/unit/defaults.test.js +364 -0
  454. package/dist/tests/unit/defaults.test.js.map +1 -0
  455. package/dist/tests/unit/dlp-backends.test.d.ts +2 -0
  456. package/dist/tests/unit/dlp-backends.test.d.ts.map +1 -0
  457. package/dist/tests/unit/dlp-backends.test.js +563 -0
  458. package/dist/tests/unit/dlp-backends.test.js.map +1 -0
  459. package/dist/tests/unit/dlp-scanner.test.d.ts +2 -0
  460. package/dist/tests/unit/dlp-scanner.test.d.ts.map +1 -0
  461. package/dist/tests/unit/dlp-scanner.test.js +739 -0
  462. package/dist/tests/unit/dlp-scanner.test.js.map +1 -0
  463. package/dist/tests/unit/error-responses.test.d.ts +2 -0
  464. package/dist/tests/unit/error-responses.test.d.ts.map +1 -0
  465. package/dist/tests/unit/error-responses.test.js +101 -0
  466. package/dist/tests/unit/error-responses.test.js.map +1 -0
  467. package/dist/tests/unit/executor-registry.test.d.ts +2 -0
  468. package/dist/tests/unit/executor-registry.test.d.ts.map +1 -0
  469. package/dist/tests/unit/executor-registry.test.js +390 -0
  470. package/dist/tests/unit/executor-registry.test.js.map +1 -0
  471. package/dist/tests/unit/forward-proxy.test.d.ts +2 -0
  472. package/dist/tests/unit/forward-proxy.test.d.ts.map +1 -0
  473. package/dist/tests/unit/forward-proxy.test.js +621 -0
  474. package/dist/tests/unit/forward-proxy.test.js.map +1 -0
  475. package/dist/tests/unit/gateway-features.test.d.ts +2 -0
  476. package/dist/tests/unit/gateway-features.test.d.ts.map +1 -0
  477. package/dist/tests/unit/gateway-features.test.js +753 -0
  478. package/dist/tests/unit/gateway-features.test.js.map +1 -0
  479. package/dist/tests/unit/http-executor.test.d.ts +2 -0
  480. package/dist/tests/unit/http-executor.test.d.ts.map +1 -0
  481. package/dist/tests/unit/http-executor.test.js +310 -0
  482. package/dist/tests/unit/http-executor.test.js.map +1 -0
  483. package/dist/tests/unit/mcp-bridge.test.d.ts +2 -0
  484. package/dist/tests/unit/mcp-bridge.test.d.ts.map +1 -0
  485. package/dist/tests/unit/mcp-bridge.test.js +1136 -0
  486. package/dist/tests/unit/mcp-bridge.test.js.map +1 -0
  487. package/dist/tests/unit/mcp-http-transport.test.d.ts +2 -0
  488. package/dist/tests/unit/mcp-http-transport.test.d.ts.map +1 -0
  489. package/dist/tests/unit/mcp-http-transport.test.js +899 -0
  490. package/dist/tests/unit/mcp-http-transport.test.js.map +1 -0
  491. package/dist/tests/unit/mcp-oauth.test.d.ts +2 -0
  492. package/dist/tests/unit/mcp-oauth.test.d.ts.map +1 -0
  493. package/dist/tests/unit/mcp-oauth.test.js +759 -0
  494. package/dist/tests/unit/mcp-oauth.test.js.map +1 -0
  495. package/dist/tests/unit/mcp-server.test.d.ts +15 -0
  496. package/dist/tests/unit/mcp-server.test.d.ts.map +1 -0
  497. package/dist/tests/unit/mcp-server.test.js +158 -0
  498. package/dist/tests/unit/mcp-server.test.js.map +1 -0
  499. package/dist/tests/unit/metrics.test.d.ts +2 -0
  500. package/dist/tests/unit/metrics.test.d.ts.map +1 -0
  501. package/dist/tests/unit/metrics.test.js +208 -0
  502. package/dist/tests/unit/metrics.test.js.map +1 -0
  503. package/dist/tests/unit/oauth.test.d.ts +2 -0
  504. package/dist/tests/unit/oauth.test.d.ts.map +1 -0
  505. package/dist/tests/unit/oauth.test.js +281 -0
  506. package/dist/tests/unit/oauth.test.js.map +1 -0
  507. package/dist/tests/unit/opa-circuit-breaker.test.d.ts +2 -0
  508. package/dist/tests/unit/opa-circuit-breaker.test.d.ts.map +1 -0
  509. package/dist/tests/unit/opa-circuit-breaker.test.js +297 -0
  510. package/dist/tests/unit/opa-circuit-breaker.test.js.map +1 -0
  511. package/dist/tests/unit/opa-engine.test.d.ts +2 -0
  512. package/dist/tests/unit/opa-engine.test.d.ts.map +1 -0
  513. package/dist/tests/unit/opa-engine.test.js +1813 -0
  514. package/dist/tests/unit/opa-engine.test.js.map +1 -0
  515. package/dist/tests/unit/pipeline-timing.test.d.ts +2 -0
  516. package/dist/tests/unit/pipeline-timing.test.d.ts.map +1 -0
  517. package/dist/tests/unit/pipeline-timing.test.js +528 -0
  518. package/dist/tests/unit/pipeline-timing.test.js.map +1 -0
  519. package/dist/tests/unit/policy-engine.test.d.ts +2 -0
  520. package/dist/tests/unit/policy-engine.test.d.ts.map +1 -0
  521. package/dist/tests/unit/policy-engine.test.js +1345 -0
  522. package/dist/tests/unit/policy-engine.test.js.map +1 -0
  523. package/dist/tests/unit/policy-store.test.d.ts +2 -0
  524. package/dist/tests/unit/policy-store.test.d.ts.map +1 -0
  525. package/dist/tests/unit/policy-store.test.js +60 -0
  526. package/dist/tests/unit/policy-store.test.js.map +1 -0
  527. package/dist/tests/unit/postgres-storage.test.d.ts +2 -0
  528. package/dist/tests/unit/postgres-storage.test.d.ts.map +1 -0
  529. package/dist/tests/unit/postgres-storage.test.js +614 -0
  530. package/dist/tests/unit/postgres-storage.test.js.map +1 -0
  531. package/dist/tests/unit/prompt-injection-backend.test.d.ts +2 -0
  532. package/dist/tests/unit/prompt-injection-backend.test.d.ts.map +1 -0
  533. package/dist/tests/unit/prompt-injection-backend.test.js +621 -0
  534. package/dist/tests/unit/prompt-injection-backend.test.js.map +1 -0
  535. package/dist/tests/unit/proxy-hardening.test.d.ts +2 -0
  536. package/dist/tests/unit/proxy-hardening.test.d.ts.map +1 -0
  537. package/dist/tests/unit/proxy-hardening.test.js +166 -0
  538. package/dist/tests/unit/proxy-hardening.test.js.map +1 -0
  539. package/dist/tests/unit/rate-limiter.test.d.ts +2 -0
  540. package/dist/tests/unit/rate-limiter.test.d.ts.map +1 -0
  541. package/dist/tests/unit/rate-limiter.test.js +443 -0
  542. package/dist/tests/unit/rate-limiter.test.js.map +1 -0
  543. package/dist/tests/unit/redis-storage.test.d.ts +2 -0
  544. package/dist/tests/unit/redis-storage.test.d.ts.map +1 -0
  545. package/dist/tests/unit/redis-storage.test.js +766 -0
  546. package/dist/tests/unit/redis-storage.test.js.map +1 -0
  547. package/dist/tests/unit/replay-engine.test.d.ts +2 -0
  548. package/dist/tests/unit/replay-engine.test.d.ts.map +1 -0
  549. package/dist/tests/unit/replay-engine.test.js +371 -0
  550. package/dist/tests/unit/replay-engine.test.js.map +1 -0
  551. package/dist/tests/unit/saas-routes.test.d.ts +2 -0
  552. package/dist/tests/unit/saas-routes.test.d.ts.map +1 -0
  553. package/dist/tests/unit/saas-routes.test.js +1399 -0
  554. package/dist/tests/unit/saas-routes.test.js.map +1 -0
  555. package/dist/tests/unit/session.test.d.ts +2 -0
  556. package/dist/tests/unit/session.test.d.ts.map +1 -0
  557. package/dist/tests/unit/session.test.js +532 -0
  558. package/dist/tests/unit/session.test.js.map +1 -0
  559. package/dist/tests/unit/slack-executor.test.d.ts +2 -0
  560. package/dist/tests/unit/slack-executor.test.d.ts.map +1 -0
  561. package/dist/tests/unit/slack-executor.test.js +209 -0
  562. package/dist/tests/unit/slack-executor.test.js.map +1 -0
  563. package/dist/tests/unit/storage-hardening.test.d.ts +2 -0
  564. package/dist/tests/unit/storage-hardening.test.d.ts.map +1 -0
  565. package/dist/tests/unit/storage-hardening.test.js +165 -0
  566. package/dist/tests/unit/storage-hardening.test.js.map +1 -0
  567. package/dist/tests/unit/storage.test.d.ts +2 -0
  568. package/dist/tests/unit/storage.test.d.ts.map +1 -0
  569. package/dist/tests/unit/storage.test.js +698 -0
  570. package/dist/tests/unit/storage.test.js.map +1 -0
  571. package/dist/tests/unit/text-normalizer.test.d.ts +2 -0
  572. package/dist/tests/unit/text-normalizer.test.d.ts.map +1 -0
  573. package/dist/tests/unit/text-normalizer.test.js +229 -0
  574. package/dist/tests/unit/text-normalizer.test.js.map +1 -0
  575. package/dist/tests/unit/tracing.test.d.ts +2 -0
  576. package/dist/tests/unit/tracing.test.d.ts.map +1 -0
  577. package/dist/tests/unit/tracing.test.js +611 -0
  578. package/dist/tests/unit/tracing.test.js.map +1 -0
  579. package/dist/tests/unit/trust-calculator.test.d.ts +2 -0
  580. package/dist/tests/unit/trust-calculator.test.d.ts.map +1 -0
  581. package/dist/tests/unit/trust-calculator.test.js +497 -0
  582. package/dist/tests/unit/trust-calculator.test.js.map +1 -0
  583. package/dist/tests/unit/ts-sdk.test.d.ts +2 -0
  584. package/dist/tests/unit/ts-sdk.test.d.ts.map +1 -0
  585. package/dist/tests/unit/ts-sdk.test.js +421 -0
  586. package/dist/tests/unit/ts-sdk.test.js.map +1 -0
  587. package/dist/tests/unit/usage-extractor-llm.test.d.ts +2 -0
  588. package/dist/tests/unit/usage-extractor-llm.test.d.ts.map +1 -0
  589. package/dist/tests/unit/usage-extractor-llm.test.js +139 -0
  590. package/dist/tests/unit/usage-extractor-llm.test.js.map +1 -0
  591. package/dist/tests/unit/usage-extractor.test.d.ts +2 -0
  592. package/dist/tests/unit/usage-extractor.test.d.ts.map +1 -0
  593. package/dist/tests/unit/usage-extractor.test.js +271 -0
  594. package/dist/tests/unit/usage-extractor.test.js.map +1 -0
  595. package/dist/tests/unit/user-stores.test.d.ts +2 -0
  596. package/dist/tests/unit/user-stores.test.d.ts.map +1 -0
  597. package/dist/tests/unit/user-stores.test.js +687 -0
  598. package/dist/tests/unit/user-stores.test.js.map +1 -0
  599. package/dist/tests/unit/validate.test.d.ts +2 -0
  600. package/dist/tests/unit/validate.test.d.ts.map +1 -0
  601. package/dist/tests/unit/validate.test.js +545 -0
  602. package/dist/tests/unit/validate.test.js.map +1 -0
  603. package/package.json +86 -0
  604. package/policy-packs/README.md +42 -0
  605. package/policy-packs/default.yaml +46 -0
  606. package/policy-packs/dev_fast.yaml +54 -0
  607. package/policy-packs/prod_strict.yaml +83 -0
@@ -0,0 +1,739 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const crypto_1 = require("crypto");
37
+ const scanner_1 = require("../../src/dlp/scanner");
38
+ // ---------------------------------------------------------------------------
39
+ // Helpers
40
+ // ---------------------------------------------------------------------------
41
+ /** Build a DLPConfig with sensible defaults for testing. */
42
+ function buildConfig(overrides = {}) {
43
+ return {
44
+ enabled: true,
45
+ scan_args: true,
46
+ scan_output: true,
47
+ secrets_detection: true,
48
+ pii_detection: true,
49
+ default_redaction_method: 'mask',
50
+ ...overrides,
51
+ };
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Tests
55
+ // ---------------------------------------------------------------------------
56
+ describe('DLPScanner', () => {
57
+ // -----------------------------------------------------------------------
58
+ // Secret Detection
59
+ // -----------------------------------------------------------------------
60
+ describe('secret detection', () => {
61
+ it('should detect AWS access keys', () => {
62
+ const scanner = new scanner_1.DLPScanner(buildConfig());
63
+ const report = scanner.scan({ key: 'AKIAIOSFODNN7EXAMPLE' });
64
+ expect(report.detected).toContain('aws_access_key');
65
+ expect(report.severity).toBe('high');
66
+ expect(report.redactions.length).toBeGreaterThan(0);
67
+ });
68
+ it('should detect AWS secret access keys', () => {
69
+ const scanner = new scanner_1.DLPScanner(buildConfig());
70
+ const report = scanner.scan({
71
+ config: 'aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY01',
72
+ });
73
+ expect(report.detected).toContain('aws_secret_key');
74
+ expect(report.severity).toBe('high');
75
+ });
76
+ it('should detect GitHub tokens (ghp_, gho_, ghu_, ghs_, ghr_)', () => {
77
+ const scanner = new scanner_1.DLPScanner(buildConfig());
78
+ const ghpToken = 'ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef0123456789';
79
+ const report = scanner.scan({ token: ghpToken });
80
+ expect(report.detected).toContain('github_token');
81
+ expect(report.severity).toBe('high');
82
+ });
83
+ it('should detect Bearer tokens', () => {
84
+ const scanner = new scanner_1.DLPScanner(buildConfig());
85
+ const report = scanner.scan({
86
+ headers: { Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.payload.signature' },
87
+ });
88
+ expect(report.detected).toContain('bearer_token');
89
+ expect(report.severity).toBe('high');
90
+ });
91
+ it('should detect JWT tokens', () => {
92
+ const scanner = new scanner_1.DLPScanner(buildConfig());
93
+ const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U';
94
+ const report = scanner.scan({ token: jwt });
95
+ expect(report.detected).toContain('jwt_token');
96
+ expect(report.severity).toBe('high');
97
+ });
98
+ it('should detect private keys', () => {
99
+ const scanner = new scanner_1.DLPScanner(buildConfig());
100
+ const report = scanner.scan({
101
+ key: '-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA...',
102
+ });
103
+ expect(report.detected).toContain('private_key');
104
+ expect(report.severity).toBe('high');
105
+ });
106
+ it('should detect EC private keys', () => {
107
+ const scanner = new scanner_1.DLPScanner(buildConfig());
108
+ const report = scanner.scan({
109
+ key: '-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIBkg...',
110
+ });
111
+ expect(report.detected).toContain('private_key');
112
+ });
113
+ it('should detect plain private keys (without algorithm prefix)', () => {
114
+ const scanner = new scanner_1.DLPScanner(buildConfig());
115
+ const report = scanner.scan({
116
+ key: '-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...',
117
+ });
118
+ expect(report.detected).toContain('private_key');
119
+ });
120
+ it('should detect password fields', () => {
121
+ const scanner = new scanner_1.DLPScanner(buildConfig());
122
+ const report = scanner.scan({
123
+ config: 'password=SuperSecret123!',
124
+ });
125
+ expect(report.detected).toContain('password_field');
126
+ expect(report.severity).toBe('high');
127
+ });
128
+ it('should detect password fields with various prefixes (passwd, pwd)', () => {
129
+ const scanner = new scanner_1.DLPScanner(buildConfig());
130
+ const report1 = scanner.scan({ field: 'passwd=MyS3cur3Pa55!' });
131
+ expect(report1.detected).toContain('password_field');
132
+ const report2 = scanner.scan({ field: 'pwd:LongEnoughPassword1' });
133
+ expect(report2.detected).toContain('password_field');
134
+ });
135
+ it('should detect generic API keys', () => {
136
+ const scanner = new scanner_1.DLPScanner(buildConfig());
137
+ const report = scanner.scan({
138
+ config: 'api_key=sk_live_abcdefghij1234567890',
139
+ });
140
+ expect(report.detected).toContain('generic_api_key');
141
+ });
142
+ it('should detect generic API keys with various formats', () => {
143
+ const scanner = new scanner_1.DLPScanner(buildConfig());
144
+ const report1 = scanner.scan({ value: 'apikey: abcdef1234567890abcdef' });
145
+ expect(report1.detected).toContain('generic_api_key');
146
+ const report2 = scanner.scan({ value: 'api-key=abcdefghijklmnopqrst' });
147
+ expect(report2.detected).toContain('generic_api_key');
148
+ });
149
+ it('should detect Slack tokens', () => {
150
+ const scanner = new scanner_1.DLPScanner(buildConfig());
151
+ const report = scanner.scan({
152
+ token: 'xoxb-123456789012-1234567890123-AbCdEfGhIjKl',
153
+ });
154
+ expect(report.detected).toContain('slack_token');
155
+ expect(report.severity).toBe('high');
156
+ });
157
+ it('should detect generic secrets', () => {
158
+ const scanner = new scanner_1.DLPScanner(buildConfig());
159
+ const report = scanner.scan({
160
+ env: 'secret=abcdefghijklmnop1234',
161
+ });
162
+ expect(report.detected).toContain('generic_secret');
163
+ });
164
+ });
165
+ // -----------------------------------------------------------------------
166
+ // PII Detection
167
+ // -----------------------------------------------------------------------
168
+ describe('PII detection', () => {
169
+ it('should detect email addresses', () => {
170
+ const scanner = new scanner_1.DLPScanner(buildConfig());
171
+ const report = scanner.scan({ contact: 'user@example.com' });
172
+ expect(report.detected).toContain('email');
173
+ expect(report.severity).toBe('medium');
174
+ });
175
+ it('should detect various email formats', () => {
176
+ const scanner = new scanner_1.DLPScanner(buildConfig());
177
+ const report = scanner.scan({
178
+ emails: 'john.doe+test@sub.domain.co.uk, admin@company.io',
179
+ });
180
+ expect(report.detected).toContain('email');
181
+ });
182
+ it('should detect US phone numbers', () => {
183
+ const scanner = new scanner_1.DLPScanner(buildConfig());
184
+ const report = scanner.scan({ phone: '(555) 123-4567' });
185
+ expect(report.detected).toContain('phone_us');
186
+ expect(report.severity).toBe('medium');
187
+ });
188
+ it('should detect phone numbers with +1 prefix', () => {
189
+ const scanner = new scanner_1.DLPScanner(buildConfig());
190
+ const report = scanner.scan({ phone: '+1-555-123-4567' });
191
+ expect(report.detected).toContain('phone_us');
192
+ });
193
+ it('should detect SSNs', () => {
194
+ const scanner = new scanner_1.DLPScanner(buildConfig());
195
+ const report = scanner.scan({ ssn: '123-45-6789' });
196
+ expect(report.detected).toContain('ssn');
197
+ expect(report.severity).toBe('high');
198
+ });
199
+ it('should detect credit card numbers', () => {
200
+ const scanner = new scanner_1.DLPScanner(buildConfig());
201
+ const report = scanner.scan({ card: '4111 1111 1111 1111' });
202
+ expect(report.detected).toContain('credit_card');
203
+ expect(report.severity).toBe('high');
204
+ });
205
+ it('should detect credit card numbers with dashes', () => {
206
+ const scanner = new scanner_1.DLPScanner(buildConfig());
207
+ const report = scanner.scan({ card: '4111-1111-1111-1111' });
208
+ expect(report.detected).toContain('credit_card');
209
+ });
210
+ it('should detect IP addresses', () => {
211
+ const scanner = new scanner_1.DLPScanner(buildConfig());
212
+ const report = scanner.scan({ ip: '192.168.1.100' });
213
+ expect(report.detected).toContain('ip_address');
214
+ expect(report.severity).toBe('low');
215
+ });
216
+ });
217
+ // -----------------------------------------------------------------------
218
+ // Recursive Scanning
219
+ // -----------------------------------------------------------------------
220
+ describe('recursive scanning', () => {
221
+ it('should scan nested objects recursively', () => {
222
+ const scanner = new scanner_1.DLPScanner(buildConfig());
223
+ const data = {
224
+ level1: {
225
+ level2: {
226
+ level3: {
227
+ secret: 'password=VerySecretPass1',
228
+ },
229
+ },
230
+ },
231
+ };
232
+ const report = scanner.scan(data);
233
+ expect(report.detected).toContain('password_field');
234
+ expect(report.redactions.length).toBeGreaterThan(0);
235
+ // Check that the path is correctly computed
236
+ const redaction = report.redactions.find((r) => r.original_type === 'password_field');
237
+ expect(redaction).toBeDefined();
238
+ expect(redaction.path).toBe('level1.level2.level3.secret');
239
+ });
240
+ it('should scan arrays', () => {
241
+ const scanner = new scanner_1.DLPScanner(buildConfig());
242
+ const data = {
243
+ items: [
244
+ 'safe text',
245
+ 'AKIAIOSFODNN7EXAMPLE',
246
+ { nested: 'user@example.com' },
247
+ ],
248
+ };
249
+ const report = scanner.scan(data);
250
+ expect(report.detected).toContain('aws_access_key');
251
+ expect(report.detected).toContain('email');
252
+ const awsRedaction = report.redactions.find((r) => r.original_type === 'aws_access_key');
253
+ expect(awsRedaction).toBeDefined();
254
+ expect(awsRedaction.path).toBe('items[1]');
255
+ const emailRedaction = report.redactions.find((r) => r.original_type === 'email');
256
+ expect(emailRedaction).toBeDefined();
257
+ expect(emailRedaction.path).toBe('items[2].nested');
258
+ });
259
+ it('should handle null values gracefully', () => {
260
+ const scanner = new scanner_1.DLPScanner(buildConfig());
261
+ const report = scanner.scan({ value: null });
262
+ expect(report.detected).toHaveLength(0);
263
+ expect(report.redactions).toHaveLength(0);
264
+ });
265
+ it('should handle undefined values gracefully', () => {
266
+ const scanner = new scanner_1.DLPScanner(buildConfig());
267
+ const report = scanner.scan(undefined);
268
+ expect(report.detected).toHaveLength(0);
269
+ expect(report.redactions).toHaveLength(0);
270
+ });
271
+ it('should handle top-level null', () => {
272
+ const scanner = new scanner_1.DLPScanner(buildConfig());
273
+ const report = scanner.scan(null);
274
+ expect(report.detected).toHaveLength(0);
275
+ });
276
+ it('should ignore non-string primitives (numbers, booleans)', () => {
277
+ const scanner = new scanner_1.DLPScanner(buildConfig());
278
+ const report = scanner.scan({ count: 42, active: true, ratio: 3.14 });
279
+ expect(report.detected).toHaveLength(0);
280
+ });
281
+ it('should use basePath when provided', () => {
282
+ const scanner = new scanner_1.DLPScanner(buildConfig());
283
+ const report = scanner.scan({ token: 'AKIAIOSFODNN7EXAMPLE' }, 'args');
284
+ const redaction = report.redactions.find((r) => r.original_type === 'aws_access_key');
285
+ expect(redaction).toBeDefined();
286
+ expect(redaction.path).toBe('args.token');
287
+ });
288
+ it('should scan top-level arrays', () => {
289
+ const scanner = new scanner_1.DLPScanner(buildConfig());
290
+ const report = scanner.scan(['AKIAIOSFODNN7EXAMPLE', 'safe']);
291
+ expect(report.detected).toContain('aws_access_key');
292
+ const redaction = report.redactions.find((r) => r.original_type === 'aws_access_key');
293
+ expect(redaction).toBeDefined();
294
+ expect(redaction.path).toBe('[0]');
295
+ });
296
+ it('should scan a plain string value', () => {
297
+ const scanner = new scanner_1.DLPScanner(buildConfig());
298
+ const report = scanner.scan('password=MySuperSecret1');
299
+ expect(report.detected).toContain('password_field');
300
+ });
301
+ });
302
+ // -----------------------------------------------------------------------
303
+ // Severity Calculation
304
+ // -----------------------------------------------------------------------
305
+ describe('severity calculation', () => {
306
+ it('should return "low" when no detections are found', () => {
307
+ const scanner = new scanner_1.DLPScanner(buildConfig());
308
+ const report = scanner.scan({ safe: 'nothing here' });
309
+ expect(report.severity).toBe('low');
310
+ });
311
+ it('should return "medium" when only medium-severity items are detected', () => {
312
+ const scanner = new scanner_1.DLPScanner(buildConfig());
313
+ // generic_api_key has medium severity, email has medium severity
314
+ const report = scanner.scan({ contact: 'user@example.com' });
315
+ expect(report.severity).toBe('medium');
316
+ });
317
+ it('should return "high" when any high-severity item is detected', () => {
318
+ const scanner = new scanner_1.DLPScanner(buildConfig());
319
+ // Mix of medium (email) and high (AWS key)
320
+ const report = scanner.scan({
321
+ contact: 'user@example.com',
322
+ key: 'AKIAIOSFODNN7EXAMPLE',
323
+ });
324
+ expect(report.severity).toBe('high');
325
+ });
326
+ it('should return "high" overriding "medium" and "low" detections', () => {
327
+ const scanner = new scanner_1.DLPScanner(buildConfig());
328
+ const report = scanner.scan({
329
+ ip: '192.168.1.1', // ip_address -> low
330
+ email: 'user@example.com', // email -> medium
331
+ ssn: '123-45-6789', // ssn -> high
332
+ });
333
+ expect(report.severity).toBe('high');
334
+ });
335
+ it('should return "low" for IP-only detection', () => {
336
+ const scanner = new scanner_1.DLPScanner(buildConfig());
337
+ const report = scanner.scan({ ip: '10.0.0.1' });
338
+ expect(report.severity).toBe('low');
339
+ });
340
+ });
341
+ // -----------------------------------------------------------------------
342
+ // Redaction Methods (static)
343
+ // -----------------------------------------------------------------------
344
+ describe('redact (static)', () => {
345
+ const testValue = 'AKIAIOSFODNN7EXAMPLE';
346
+ it('should mask values (keep first 4 chars, replace rest with x)', () => {
347
+ const result = scanner_1.DLPScanner.redact(testValue, 'mask');
348
+ expect(result).toBe('AKIA' + 'x'.repeat(Math.min(testValue.length - 4, 20)));
349
+ expect(result.startsWith('AKIA')).toBe(true);
350
+ // The rest should be x's
351
+ expect(result.slice(4)).toMatch(/^x+$/);
352
+ });
353
+ it('should mask short values (length <= 4) as "xxxx"', () => {
354
+ expect(scanner_1.DLPScanner.redact('abc', 'mask')).toBe('xxxx');
355
+ expect(scanner_1.DLPScanner.redact('abcd', 'mask')).toBe('xxxx');
356
+ });
357
+ it('should cap mask replacement at 20 x characters', () => {
358
+ const longValue = 'abcd' + 'z'.repeat(50);
359
+ const result = scanner_1.DLPScanner.redact(longValue, 'mask');
360
+ expect(result).toBe('abcd' + 'x'.repeat(20));
361
+ });
362
+ it('should hash values with SHA-256 prefix', () => {
363
+ const result = scanner_1.DLPScanner.redact(testValue, 'hash');
364
+ expect(result).toMatch(/^HASH:[0-9a-f]{16}$/);
365
+ // Verify it matches the expected hash
366
+ const expectedHash = (0, crypto_1.createHash)('sha256').update(testValue).digest('hex').slice(0, 16);
367
+ expect(result).toBe(`HASH:${expectedHash}`);
368
+ });
369
+ it('should drop values entirely', () => {
370
+ expect(scanner_1.DLPScanner.redact(testValue, 'drop')).toBe('[REDACTED]');
371
+ });
372
+ it('should tokenize values with SHA-256 prefix', () => {
373
+ const result = scanner_1.DLPScanner.redact(testValue, 'tokenize');
374
+ expect(result).toMatch(/^\{\{REDACTED_[0-9a-f]{16}\}\}$/);
375
+ // Verify determinism
376
+ const expectedToken = (0, crypto_1.createHash)('sha256').update(testValue).digest('hex').slice(0, 16);
377
+ expect(result).toBe(`{{REDACTED_${expectedToken}}}`);
378
+ });
379
+ it('should default to [REDACTED] for unknown method', () => {
380
+ const result = scanner_1.DLPScanner.redact(testValue, 'unknown');
381
+ expect(result).toBe('[REDACTED]');
382
+ });
383
+ it('should produce deterministic results for hash and tokenize', () => {
384
+ const v = 'consistent_value_for_testing_123';
385
+ expect(scanner_1.DLPScanner.redact(v, 'hash')).toBe(scanner_1.DLPScanner.redact(v, 'hash'));
386
+ expect(scanner_1.DLPScanner.redact(v, 'tokenize')).toBe(scanner_1.DLPScanner.redact(v, 'tokenize'));
387
+ });
388
+ });
389
+ // -----------------------------------------------------------------------
390
+ // Entropy Calculation
391
+ // -----------------------------------------------------------------------
392
+ describe('calculateEntropy (static)', () => {
393
+ it('should return 0 for an empty string', () => {
394
+ expect(scanner_1.DLPScanner.calculateEntropy('')).toBe(0);
395
+ });
396
+ it('should return 0 for a single-character repeated string', () => {
397
+ expect(scanner_1.DLPScanner.calculateEntropy('aaaaaaa')).toBe(0);
398
+ });
399
+ it('should return 1 for a two-character string with equal distribution', () => {
400
+ // "ab" -> each char appears once out of 2 -> -2 * (0.5 * log2(0.5)) = 1
401
+ expect(scanner_1.DLPScanner.calculateEntropy('ab')).toBeCloseTo(1.0, 5);
402
+ });
403
+ it('should return higher entropy for random-looking strings', () => {
404
+ const lowEntropy = 'aaaaaaaabbbbbbbb';
405
+ const highEntropy = 'aB3$xZ9!qW7&mK2@';
406
+ expect(scanner_1.DLPScanner.calculateEntropy(highEntropy)).toBeGreaterThan(scanner_1.DLPScanner.calculateEntropy(lowEntropy));
407
+ });
408
+ it('should compute correct entropy for a known distribution', () => {
409
+ // "aabb" -> a:2, b:2 -> -2*(2/4 * log2(2/4)) = -2*(0.5*-1) = 1.0
410
+ expect(scanner_1.DLPScanner.calculateEntropy('aabb')).toBeCloseTo(1.0, 5);
411
+ });
412
+ it('should return higher entropy for more varied character sets', () => {
413
+ // 'aaabbbcccddd' has 3 unique chars each appearing 4 times -> low entropy
414
+ const lowVariety = 'aaabbbcccdddeeee';
415
+ // 'aB3$xZ9!qW7&mK2@' has 16 unique chars each appearing once -> high entropy
416
+ const highVariety = 'aB3$xZ9!qW7&mK2@';
417
+ expect(scanner_1.DLPScanner.calculateEntropy(highVariety)).toBeGreaterThan(scanner_1.DLPScanner.calculateEntropy(lowVariety));
418
+ });
419
+ });
420
+ // -----------------------------------------------------------------------
421
+ // High Entropy Detection
422
+ // -----------------------------------------------------------------------
423
+ describe('isHighEntropy (static)', () => {
424
+ it('should return false for short strings (< 16 chars)', () => {
425
+ expect(scanner_1.DLPScanner.isHighEntropy('aB3$xZ9!')).toBe(false);
426
+ expect(scanner_1.DLPScanner.isHighEntropy('123456789012345')).toBe(false); // 15 chars
427
+ });
428
+ it('should return false for low-entropy long strings', () => {
429
+ const lowEntropy = 'aaaaaaaaaaaaaaaa'; // 16 chars, entropy = 0
430
+ expect(scanner_1.DLPScanner.isHighEntropy(lowEntropy)).toBe(false);
431
+ });
432
+ it('should return true for high-entropy strings of sufficient length', () => {
433
+ // A base64-encoded random-looking string with many unique chars
434
+ const highEntropyStr = 'aB3$xZ9!qW7&mK2@pL5^tY8#';
435
+ const entropy = scanner_1.DLPScanner.calculateEntropy(highEntropyStr);
436
+ // Verify the string actually has high entropy first
437
+ expect(entropy).toBeGreaterThanOrEqual(4.0);
438
+ expect(scanner_1.DLPScanner.isHighEntropy(highEntropyStr)).toBe(true);
439
+ });
440
+ it('should respect custom threshold parameter', () => {
441
+ // A string with moderate entropy
442
+ const str = 'abcdefghijklmnop'; // 16 unique chars, entropy = 4.0
443
+ const entropy = scanner_1.DLPScanner.calculateEntropy(str);
444
+ // With a threshold below its entropy -> true
445
+ expect(scanner_1.DLPScanner.isHighEntropy(str, entropy - 0.1)).toBe(true);
446
+ // With a threshold above its entropy -> false
447
+ expect(scanner_1.DLPScanner.isHighEntropy(str, entropy + 0.1)).toBe(false);
448
+ });
449
+ it('should use default threshold of 4.5', () => {
450
+ // Entropy of 'abcdefghijklmnop' = log2(16) = 4.0, below 4.5
451
+ expect(scanner_1.DLPScanner.isHighEntropy('abcdefghijklmnop')).toBe(false);
452
+ });
453
+ });
454
+ // -----------------------------------------------------------------------
455
+ // Disabled DLP
456
+ // -----------------------------------------------------------------------
457
+ describe('disabled DLP', () => {
458
+ it('should return empty report when DLP is disabled', () => {
459
+ const scanner = new scanner_1.DLPScanner(buildConfig({ enabled: false }));
460
+ const report = scanner.scan({
461
+ key: 'AKIAIOSFODNN7EXAMPLE',
462
+ email: 'user@example.com',
463
+ password: 'password=SuperSecretPassword1',
464
+ });
465
+ expect(report.detected).toHaveLength(0);
466
+ expect(report.redactions).toHaveLength(0);
467
+ expect(report.severity).toBe('low');
468
+ });
469
+ });
470
+ // -----------------------------------------------------------------------
471
+ // Selective Scanning (secrets only, PII only)
472
+ // -----------------------------------------------------------------------
473
+ describe('selective scanning', () => {
474
+ it('should detect only secrets when PII detection is disabled', () => {
475
+ const scanner = new scanner_1.DLPScanner(buildConfig({ pii_detection: false }));
476
+ const report = scanner.scan({
477
+ key: 'AKIAIOSFODNN7EXAMPLE',
478
+ email: 'user@example.com',
479
+ ssn: '123-45-6789',
480
+ });
481
+ expect(report.detected).toContain('aws_access_key');
482
+ expect(report.detected).not.toContain('email');
483
+ expect(report.detected).not.toContain('ssn');
484
+ });
485
+ it('should detect only PII when secrets detection is disabled', () => {
486
+ const scanner = new scanner_1.DLPScanner(buildConfig({ secrets_detection: false }));
487
+ const report = scanner.scan({
488
+ key: 'AKIAIOSFODNN7EXAMPLE',
489
+ email: 'user@example.com',
490
+ ssn: '123-45-6789',
491
+ });
492
+ expect(report.detected).not.toContain('aws_access_key');
493
+ expect(report.detected).toContain('email');
494
+ expect(report.detected).toContain('ssn');
495
+ });
496
+ it('should detect nothing when both secrets and PII detection are disabled', () => {
497
+ const scanner = new scanner_1.DLPScanner(buildConfig({ secrets_detection: false, pii_detection: false }));
498
+ const report = scanner.scan({
499
+ key: 'AKIAIOSFODNN7EXAMPLE',
500
+ email: 'user@example.com',
501
+ });
502
+ expect(report.detected).toHaveLength(0);
503
+ expect(report.redactions).toHaveLength(0);
504
+ });
505
+ });
506
+ // -----------------------------------------------------------------------
507
+ // Redaction application (applyRedactions)
508
+ // -----------------------------------------------------------------------
509
+ describe('applyRedactions', () => {
510
+ it('should apply mask redaction to a nested path', () => {
511
+ const scanner = new scanner_1.DLPScanner(buildConfig());
512
+ const data = {
513
+ headers: {
514
+ Authorization: 'Bearer eyJhbGciOiJIUzI1NiJ9.payload.sig',
515
+ },
516
+ };
517
+ const redactions = [
518
+ { path: 'headers.Authorization', method: 'mask', original_type: 'bearer_token' },
519
+ ];
520
+ const result = scanner.applyRedactions(data, redactions);
521
+ // The original should not be mutated
522
+ expect(data.headers.Authorization).toBe('Bearer eyJhbGciOiJIUzI1NiJ9.payload.sig');
523
+ // The redacted result should not contain the original bearer token
524
+ expect(result.headers.Authorization).not.toBe(data.headers.Authorization);
525
+ });
526
+ it('should apply drop redaction', () => {
527
+ const scanner = new scanner_1.DLPScanner(buildConfig());
528
+ const data = { secret: 'AKIAIOSFODNN7EXAMPLE' };
529
+ const redactions = [
530
+ { path: 'secret', method: 'drop', original_type: 'aws_access_key' },
531
+ ];
532
+ const result = scanner.applyRedactions(data, redactions);
533
+ // The entire matched portion is replaced with [REDACTED]
534
+ expect(result.secret).toContain('[REDACTED]');
535
+ });
536
+ it('should return data unchanged when no redactions are provided', () => {
537
+ const scanner = new scanner_1.DLPScanner(buildConfig());
538
+ const data = { key: 'value' };
539
+ const result = scanner.applyRedactions(data, []);
540
+ expect(result).toEqual(data);
541
+ });
542
+ it('should handle array paths in redactions', () => {
543
+ const scanner = new scanner_1.DLPScanner(buildConfig());
544
+ const data = {
545
+ items: ['safe', 'AKIAIOSFODNN7EXAMPLE'],
546
+ };
547
+ const redactions = [
548
+ { path: 'items[1]', method: 'drop', original_type: 'aws_access_key' },
549
+ ];
550
+ const result = scanner.applyRedactions(data, redactions);
551
+ expect(result.items[0]).toBe('safe');
552
+ expect(result.items[1]).toContain('[REDACTED]');
553
+ });
554
+ it('should not mutate the original data', () => {
555
+ const scanner = new scanner_1.DLPScanner(buildConfig());
556
+ const original = { secret: 'AKIAIOSFODNN7EXAMPLE' };
557
+ const redactions = [
558
+ { path: 'secret', method: 'drop', original_type: 'aws_access_key' },
559
+ ];
560
+ scanner.applyRedactions(original, redactions);
561
+ expect(original.secret).toBe('AKIAIOSFODNN7EXAMPLE');
562
+ });
563
+ it('should skip silently when path cannot be resolved', () => {
564
+ const scanner = new scanner_1.DLPScanner(buildConfig());
565
+ const data = { key: 'value' };
566
+ const redactions = [
567
+ { path: 'nonexistent.deep.path', method: 'drop' },
568
+ ];
569
+ const result = scanner.applyRedactions(data, redactions);
570
+ expect(result).toEqual({ key: 'value' });
571
+ });
572
+ it('should skip silently when the leaf is not a string', () => {
573
+ const scanner = new scanner_1.DLPScanner(buildConfig());
574
+ const data = { count: 42 };
575
+ const redactions = [
576
+ { path: 'count', method: 'mask' },
577
+ ];
578
+ const result = scanner.applyRedactions(data, redactions);
579
+ expect(result.count).toBe(42);
580
+ });
581
+ });
582
+ // -----------------------------------------------------------------------
583
+ // parsePath (static)
584
+ // -----------------------------------------------------------------------
585
+ describe('parsePath (static)', () => {
586
+ it('should parse dot-notation paths', () => {
587
+ expect(scanner_1.DLPScanner.parsePath('a.b.c')).toEqual(['a', 'b', 'c']);
588
+ });
589
+ it('should parse bracket-notation paths', () => {
590
+ expect(scanner_1.DLPScanner.parsePath('items[0]')).toEqual(['items', '0']);
591
+ });
592
+ it('should parse mixed dot and bracket notation', () => {
593
+ expect(scanner_1.DLPScanner.parsePath('items[0].value')).toEqual(['items', '0', 'value']);
594
+ });
595
+ it('should parse standalone bracket path', () => {
596
+ expect(scanner_1.DLPScanner.parsePath('[0]')).toEqual(['0']);
597
+ });
598
+ it('should return empty array for empty string', () => {
599
+ expect(scanner_1.DLPScanner.parsePath('')).toEqual([]);
600
+ });
601
+ it('should parse single segment', () => {
602
+ expect(scanner_1.DLPScanner.parsePath('key')).toEqual(['key']);
603
+ });
604
+ });
605
+ // -----------------------------------------------------------------------
606
+ // deepClone (static)
607
+ // -----------------------------------------------------------------------
608
+ describe('deepClone (static)', () => {
609
+ it('should deep clone objects', () => {
610
+ const original = { a: { b: { c: 1 } } };
611
+ const cloned = scanner_1.DLPScanner.deepClone(original);
612
+ expect(cloned).toEqual(original);
613
+ cloned.a.b.c = 99;
614
+ expect(original.a.b.c).toBe(1);
615
+ });
616
+ it('should deep clone arrays', () => {
617
+ const original = [1, [2, 3], { a: 4 }];
618
+ const cloned = scanner_1.DLPScanner.deepClone(original);
619
+ expect(cloned).toEqual(original);
620
+ cloned[2].a = 99;
621
+ expect(original[2].a).toBe(4);
622
+ });
623
+ it('should return null for null', () => {
624
+ expect(scanner_1.DLPScanner.deepClone(null)).toBe(null);
625
+ });
626
+ it('should return undefined for undefined', () => {
627
+ expect(scanner_1.DLPScanner.deepClone(undefined)).toBe(undefined);
628
+ });
629
+ it('should return primitives as-is', () => {
630
+ expect(scanner_1.DLPScanner.deepClone(42)).toBe(42);
631
+ expect(scanner_1.DLPScanner.deepClone('hello')).toBe('hello');
632
+ expect(scanner_1.DLPScanner.deepClone(true)).toBe(true);
633
+ });
634
+ });
635
+ // -----------------------------------------------------------------------
636
+ // Deduplication
637
+ // -----------------------------------------------------------------------
638
+ describe('detection deduplication', () => {
639
+ it('should deduplicate detection names in the report', () => {
640
+ const scanner = new scanner_1.DLPScanner(buildConfig());
641
+ const report = scanner.scan({
642
+ key1: 'AKIAIOSFODNN7EXAMPLE',
643
+ key2: 'AKIAIOSFODNN7FOOBAR1',
644
+ });
645
+ // Both are aws_access_key but should appear only once in detected
646
+ const awsCount = report.detected.filter((d) => d === 'aws_access_key').length;
647
+ expect(awsCount).toBe(1);
648
+ // But there should be 2 redactions (one per field)
649
+ const awsRedactions = report.redactions.filter((r) => r.original_type === 'aws_access_key');
650
+ expect(awsRedactions.length).toBe(2);
651
+ });
652
+ });
653
+ // -----------------------------------------------------------------------
654
+ // Redaction method from config
655
+ // -----------------------------------------------------------------------
656
+ describe('uses configured default_redaction_method', () => {
657
+ it('should use "hash" as the redaction method when configured', () => {
658
+ const scanner = new scanner_1.DLPScanner(buildConfig({ default_redaction_method: 'hash' }));
659
+ const report = scanner.scan({ key: 'AKIAIOSFODNN7EXAMPLE' });
660
+ for (const redaction of report.redactions) {
661
+ expect(redaction.method).toBe('hash');
662
+ }
663
+ });
664
+ it('should use "drop" as the redaction method when configured', () => {
665
+ const scanner = new scanner_1.DLPScanner(buildConfig({ default_redaction_method: 'drop' }));
666
+ const report = scanner.scan({ email: 'user@example.com' });
667
+ for (const redaction of report.redactions) {
668
+ expect(redaction.method).toBe('drop');
669
+ }
670
+ });
671
+ it('should use "tokenize" as the redaction method when configured', () => {
672
+ const scanner = new scanner_1.DLPScanner(buildConfig({ default_redaction_method: 'tokenize' }));
673
+ const report = scanner.scan({ key: 'AKIAIOSFODNN7EXAMPLE' });
674
+ for (const redaction of report.redactions) {
675
+ expect(redaction.method).toBe('tokenize');
676
+ }
677
+ });
678
+ });
679
+ // -----------------------------------------------------------------------
680
+ // Multiple detections in single string
681
+ // -----------------------------------------------------------------------
682
+ describe('multiple detections in a single string', () => {
683
+ it('should detect multiple secret types in one string', () => {
684
+ const scanner = new scanner_1.DLPScanner(buildConfig());
685
+ const combined = 'key=AKIAIOSFODNN7EXAMPLE token=xoxb-1234567890-1234567890-abcdefghij';
686
+ const report = scanner.scan({ value: combined });
687
+ expect(report.detected).toContain('aws_access_key');
688
+ expect(report.detected).toContain('slack_token');
689
+ });
690
+ });
691
+ // -----------------------------------------------------------------------
692
+ // DLP Bypass Vector Tests
693
+ // -----------------------------------------------------------------------
694
+ describe('DLP bypass vectors', () => {
695
+ // Use RegexDLPBackend directly for these tests since it has the
696
+ // normalization logic (zero-width stripping, homoglyph replacement, base64 decode)
697
+ let backend;
698
+ beforeAll(async () => {
699
+ const { RegexDLPBackend } = await Promise.resolve().then(() => __importStar(require('../../src/dlp/regex-backend')));
700
+ backend = new RegexDLPBackend();
701
+ });
702
+ it('should detect base64-encoded AWS key', () => {
703
+ const awsKey = 'AKIAIOSFODNN7EXAMPLE';
704
+ const encoded = Buffer.from(awsKey).toString('base64');
705
+ const detections = backend.scanString(encoded);
706
+ // Should detect the AWS key either directly or via base64 decoding
707
+ const hasAwsDetection = detections.some(d => d.pattern_name === 'aws_access_key' || d.pattern_name === 'base64:aws_access_key');
708
+ expect(hasAwsDetection).toBe(true);
709
+ });
710
+ it('should detect AWS key with Unicode homoglyph (Cyrillic A)', () => {
711
+ // Replace ASCII 'A' with Cyrillic 'A' (U+0410) in the AKIA prefix
712
+ const homoglyphKey = '\u0410KI\u0410IOSFODNN7EXAMPLE';
713
+ const detections = backend.scanString(homoglyphKey);
714
+ const hasAwsDetection = detections.some(d => d.pattern_name === 'aws_access_key');
715
+ expect(hasAwsDetection).toBe(true);
716
+ });
717
+ it('should detect AWS key with zero-width characters inserted', () => {
718
+ // Insert zero-width space (U+200B) inside the key
719
+ const zwKey = 'AKI\u200BAIOSFODNN7EXAMPLE';
720
+ const detections = backend.scanString(zwKey);
721
+ const hasAwsDetection = detections.some(d => d.pattern_name === 'aws_access_key');
722
+ expect(hasAwsDetection).toBe(true);
723
+ });
724
+ it('should NOT detect secrets nested beyond depth limit (> 32 levels)', () => {
725
+ const scanner = new scanner_1.DLPScanner(buildConfig());
726
+ // Build an object nested 33 levels deep with a secret at the bottom
727
+ let obj = { secret: 'AKIAIOSFODNN7EXAMPLE' };
728
+ for (let i = 0; i < 33; i++) {
729
+ obj = { nested: obj };
730
+ }
731
+ const report = scanner.scan(obj);
732
+ // The secret is at depth 34 (33 wrapping levels + 1 for the 'secret' key),
733
+ // which exceeds MAX_SCAN_DEPTH of 32, so it should NOT be detected
734
+ expect(report.detected).not.toContain('aws_access_key');
735
+ expect(report.redactions).toHaveLength(0);
736
+ });
737
+ });
738
+ });
739
+ //# sourceMappingURL=dlp-scanner.test.js.map