shield360 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/README.md +330 -3
  2. package/dist/__tests__/build-info.test.js +8 -1
  3. package/dist/__tests__/build-info.test.js.map +1 -1
  4. package/dist/__tests__/code-location.test.js +1 -1
  5. package/dist/__tests__/destination.test.js +15 -0
  6. package/dist/__tests__/destination.test.js.map +1 -1
  7. package/dist/__tests__/masking.test.d.ts +1 -0
  8. package/dist/__tests__/masking.test.js +66 -0
  9. package/dist/__tests__/masking.test.js.map +1 -0
  10. package/dist/__tests__/register.e2e.test.d.ts +1 -0
  11. package/dist/__tests__/register.e2e.test.js +279 -0
  12. package/dist/__tests__/register.e2e.test.js.map +1 -0
  13. package/dist/__tests__/register.test.js +60 -0
  14. package/dist/__tests__/register.test.js.map +1 -1
  15. package/dist/agents/__tests__/agents.test.d.ts +1 -0
  16. package/dist/agents/__tests__/agents.test.js +529 -0
  17. package/dist/agents/__tests__/agents.test.js.map +1 -0
  18. package/dist/agents/index.d.ts +15 -0
  19. package/dist/agents/index.js +25 -0
  20. package/dist/agents/index.js.map +1 -0
  21. package/dist/agents/passport.d.ts +92 -0
  22. package/dist/agents/passport.js +301 -0
  23. package/dist/agents/passport.js.map +1 -0
  24. package/dist/agents/policy.d.ts +24 -0
  25. package/dist/agents/policy.js +93 -0
  26. package/dist/agents/policy.js.map +1 -0
  27. package/dist/agents/replay.d.ts +20 -0
  28. package/dist/agents/replay.js +47 -0
  29. package/dist/agents/replay.js.map +1 -0
  30. package/dist/agents/report.d.ts +30 -0
  31. package/dist/agents/report.js +93 -0
  32. package/dist/agents/report.js.map +1 -0
  33. package/dist/agents/types.d.ts +148 -0
  34. package/dist/agents/types.js +37 -0
  35. package/dist/agents/types.js.map +1 -0
  36. package/dist/agents/verifier.d.ts +33 -0
  37. package/dist/agents/verifier.js +276 -0
  38. package/dist/agents/verifier.js.map +1 -0
  39. package/dist/ai-security/__tests__/bench.test.d.ts +1 -0
  40. package/dist/ai-security/__tests__/bench.test.js +50 -0
  41. package/dist/ai-security/__tests__/bench.test.js.map +1 -0
  42. package/dist/ai-security/__tests__/checks.test.d.ts +1 -0
  43. package/dist/ai-security/__tests__/checks.test.js +248 -0
  44. package/dist/ai-security/__tests__/checks.test.js.map +1 -0
  45. package/dist/ai-security/__tests__/config.test.d.ts +1 -0
  46. package/dist/ai-security/__tests__/config.test.js +164 -0
  47. package/dist/ai-security/__tests__/config.test.js.map +1 -0
  48. package/dist/ai-security/__tests__/detection.test.d.ts +1 -0
  49. package/dist/ai-security/__tests__/detection.test.js +114 -0
  50. package/dist/ai-security/__tests__/detection.test.js.map +1 -0
  51. package/dist/ai-security/__tests__/fixtures.d.ts +8 -0
  52. package/dist/ai-security/__tests__/fixtures.js +30 -0
  53. package/dist/ai-security/__tests__/fixtures.js.map +1 -0
  54. package/dist/ai-security/__tests__/hooks.test.d.ts +1 -0
  55. package/dist/ai-security/__tests__/hooks.test.js +174 -0
  56. package/dist/ai-security/__tests__/hooks.test.js.map +1 -0
  57. package/dist/ai-security/__tests__/stream.test.d.ts +1 -0
  58. package/dist/ai-security/__tests__/stream.test.js +85 -0
  59. package/dist/ai-security/__tests__/stream.test.js.map +1 -0
  60. package/dist/ai-security/config.d.ts +94 -0
  61. package/dist/ai-security/config.js +241 -0
  62. package/dist/ai-security/config.js.map +1 -0
  63. package/dist/ai-security/context.d.ts +45 -0
  64. package/dist/ai-security/context.js +108 -0
  65. package/dist/ai-security/context.js.map +1 -0
  66. package/dist/ai-security/custom-kinds.d.ts +23 -0
  67. package/dist/ai-security/custom-kinds.js +97 -0
  68. package/dist/ai-security/custom-kinds.js.map +1 -0
  69. package/dist/ai-security/events.d.ts +77 -0
  70. package/dist/ai-security/events.js +153 -0
  71. package/dist/ai-security/events.js.map +1 -0
  72. package/dist/ai-security/hooks.d.ts +48 -0
  73. package/dist/ai-security/hooks.js +461 -0
  74. package/dist/ai-security/hooks.js.map +1 -0
  75. package/dist/ai-security/index.d.ts +209 -0
  76. package/dist/ai-security/index.js +587 -0
  77. package/dist/ai-security/index.js.map +1 -0
  78. package/dist/ai-security/injection-rules.json +1024 -0
  79. package/dist/ai-security/injection.d.ts +46 -0
  80. package/dist/ai-security/injection.js +635 -0
  81. package/dist/ai-security/injection.js.map +1 -0
  82. package/dist/ai-security/jailbreak.d.ts +38 -0
  83. package/dist/ai-security/jailbreak.js +73 -0
  84. package/dist/ai-security/jailbreak.js.map +1 -0
  85. package/dist/ai-security/limits.d.ts +84 -0
  86. package/dist/ai-security/limits.js +195 -0
  87. package/dist/ai-security/limits.js.map +1 -0
  88. package/dist/ai-security/mcp.d.ts +82 -0
  89. package/dist/ai-security/mcp.js +150 -0
  90. package/dist/ai-security/mcp.js.map +1 -0
  91. package/dist/ai-security/output.d.ts +107 -0
  92. package/dist/ai-security/output.js +390 -0
  93. package/dist/ai-security/output.js.map +1 -0
  94. package/dist/ai-security/policy.d.ts +125 -0
  95. package/dist/ai-security/policy.js +196 -0
  96. package/dist/ai-security/policy.js.map +1 -0
  97. package/dist/ai-security/rag.d.ts +70 -0
  98. package/dist/ai-security/rag.js +174 -0
  99. package/dist/ai-security/rag.js.map +1 -0
  100. package/dist/ai-security/tool-rules.json +203 -0
  101. package/dist/ai-security/tools.d.ts +46 -0
  102. package/dist/ai-security/tools.js +62 -0
  103. package/dist/ai-security/tools.js.map +1 -0
  104. package/dist/budgets/__tests__/budgets.test.d.ts +1 -0
  105. package/dist/budgets/__tests__/budgets.test.js +134 -0
  106. package/dist/budgets/__tests__/budgets.test.js.map +1 -0
  107. package/dist/budgets/auto.d.ts +25 -0
  108. package/dist/budgets/auto.js +63 -0
  109. package/dist/budgets/auto.js.map +1 -0
  110. package/dist/budgets/index.d.ts +110 -0
  111. package/dist/budgets/index.js +239 -0
  112. package/dist/budgets/index.js.map +1 -0
  113. package/dist/customer/__tests__/customer.test.d.ts +1 -0
  114. package/dist/customer/__tests__/customer.test.js +155 -0
  115. package/dist/customer/__tests__/customer.test.js.map +1 -0
  116. package/dist/customer/index.d.ts +48 -0
  117. package/dist/customer/index.js +132 -0
  118. package/dist/customer/index.js.map +1 -0
  119. package/dist/destination.d.ts +14 -0
  120. package/dist/destination.js +16 -0
  121. package/dist/destination.js.map +1 -1
  122. package/dist/feedback/__tests__/feedback.test.d.ts +1 -0
  123. package/dist/feedback/__tests__/feedback.test.js +80 -0
  124. package/dist/feedback/__tests__/feedback.test.js.map +1 -0
  125. package/dist/feedback/index.d.ts +48 -0
  126. package/dist/feedback/index.js +97 -0
  127. package/dist/feedback/index.js.map +1 -0
  128. package/dist/flags/__tests__/flags.test.d.ts +1 -0
  129. package/dist/flags/__tests__/flags.test.js +301 -0
  130. package/dist/flags/__tests__/flags.test.js.map +1 -0
  131. package/dist/flags/client.d.ts +131 -0
  132. package/dist/flags/client.js +301 -0
  133. package/dist/flags/client.js.map +1 -0
  134. package/dist/flags/engine.d.ts +200 -0
  135. package/dist/flags/engine.js +677 -0
  136. package/dist/flags/engine.js.map +1 -0
  137. package/dist/flags/index.d.ts +4 -0
  138. package/dist/flags/index.js +16 -0
  139. package/dist/flags/index.js.map +1 -0
  140. package/dist/guard/__tests__/findings.test.js +1 -1
  141. package/dist/guard/__tests__/report.test.js +67 -0
  142. package/dist/guard/__tests__/report.test.js.map +1 -1
  143. package/dist/guard/heartbeat.d.ts +34 -0
  144. package/dist/guard/heartbeat.js +83 -0
  145. package/dist/guard/heartbeat.js.map +1 -0
  146. package/dist/guard/integration.d.ts +9 -0
  147. package/dist/guard/integration.js +4 -2
  148. package/dist/guard/integration.js.map +1 -1
  149. package/dist/guard/report.d.ts +24 -1
  150. package/dist/guard/report.js +67 -18
  151. package/dist/guard/report.js.map +1 -1
  152. package/dist/index.d.ts +88 -0
  153. package/dist/index.js +203 -2
  154. package/dist/index.js.map +1 -1
  155. package/dist/instrumentation/__tests__/langchain-wrapper.test.js +1 -1
  156. package/dist/instrumentation/__tests__/langchain-wrapper.test.js.map +1 -1
  157. package/dist/instrumentation/anthropic/wrapper.js +4 -0
  158. package/dist/instrumentation/anthropic/wrapper.js.map +1 -1
  159. package/dist/instrumentation/openai/wrapper.js +6 -0
  160. package/dist/instrumentation/openai/wrapper.js.map +1 -1
  161. package/dist/masking.d.ts +42 -0
  162. package/dist/masking.js +197 -0
  163. package/dist/masking.js.map +1 -0
  164. package/dist/otel/__tests__/app-logs-safety.test.d.ts +1 -0
  165. package/dist/otel/__tests__/app-logs-safety.test.js +129 -0
  166. package/dist/otel/__tests__/app-logs-safety.test.js.map +1 -0
  167. package/dist/otel/__tests__/app-logs.test.d.ts +1 -0
  168. package/dist/otel/__tests__/app-logs.test.js +269 -0
  169. package/dist/otel/__tests__/app-logs.test.js.map +1 -0
  170. package/dist/otel/__tests__/log-auto.test.d.ts +1 -0
  171. package/dist/otel/__tests__/log-auto.test.js +125 -0
  172. package/dist/otel/__tests__/log-auto.test.js.map +1 -0
  173. package/dist/otel/__tests__/log-bridges.test.d.ts +1 -0
  174. package/dist/otel/__tests__/log-bridges.test.js +170 -0
  175. package/dist/otel/__tests__/log-bridges.test.js.map +1 -0
  176. package/dist/otel/__tests__/system-metrics.test.d.ts +1 -0
  177. package/dist/otel/__tests__/system-metrics.test.js +79 -0
  178. package/dist/otel/__tests__/system-metrics.test.js.map +1 -0
  179. package/dist/otel/app-logs.d.ts +80 -0
  180. package/dist/otel/app-logs.js +195 -0
  181. package/dist/otel/app-logs.js.map +1 -0
  182. package/dist/otel/build-info.d.ts +2 -1
  183. package/dist/otel/build-info.js +3 -2
  184. package/dist/otel/build-info.js.map +1 -1
  185. package/dist/otel/events.d.ts +1 -0
  186. package/dist/otel/events.js +22 -13
  187. package/dist/otel/events.js.map +1 -1
  188. package/dist/otel/log-auto.d.ts +44 -0
  189. package/dist/otel/log-auto.js +200 -0
  190. package/dist/otel/log-auto.js.map +1 -0
  191. package/dist/otel/log-bridges.d.ts +54 -0
  192. package/dist/otel/log-bridges.js +307 -0
  193. package/dist/otel/log-bridges.js.map +1 -0
  194. package/dist/otel/metrics.js +1 -1
  195. package/dist/otel/metrics.js.map +1 -1
  196. package/dist/otel/system-metrics.d.ts +39 -0
  197. package/dist/otel/system-metrics.js +166 -0
  198. package/dist/otel/system-metrics.js.map +1 -0
  199. package/dist/otel/tracing.js +6 -2
  200. package/dist/otel/tracing.js.map +1 -1
  201. package/dist/protect/__tests__/protect.test.js +4 -0
  202. package/dist/protect/__tests__/protect.test.js.map +1 -1
  203. package/dist/protect/index.js +9 -4
  204. package/dist/protect/index.js.map +1 -1
  205. package/dist/rasp/__tests__/auto-http.test.d.ts +1 -0
  206. package/dist/rasp/__tests__/auto-http.test.js +136 -0
  207. package/dist/rasp/__tests__/auto-http.test.js.map +1 -0
  208. package/dist/rasp/__tests__/baseline.test.d.ts +1 -0
  209. package/dist/rasp/__tests__/baseline.test.js +86 -0
  210. package/dist/rasp/__tests__/baseline.test.js.map +1 -0
  211. package/dist/rasp/__tests__/benign-corpus.test.d.ts +1 -0
  212. package/dist/rasp/__tests__/benign-corpus.test.js +68 -0
  213. package/dist/rasp/__tests__/benign-corpus.test.js.map +1 -0
  214. package/dist/rasp/__tests__/capture-context.test.d.ts +1 -0
  215. package/dist/rasp/__tests__/capture-context.test.js +135 -0
  216. package/dist/rasp/__tests__/capture-context.test.js.map +1 -0
  217. package/dist/rasp/__tests__/code-hook.test.d.ts +1 -0
  218. package/dist/rasp/__tests__/code-hook.test.js +218 -0
  219. package/dist/rasp/__tests__/code-hook.test.js.map +1 -0
  220. package/dist/rasp/__tests__/config-client.test.d.ts +1 -0
  221. package/dist/rasp/__tests__/config-client.test.js +283 -0
  222. package/dist/rasp/__tests__/config-client.test.js.map +1 -0
  223. package/dist/rasp/__tests__/corpus.d.ts +13 -0
  224. package/dist/rasp/__tests__/corpus.js +111 -0
  225. package/dist/rasp/__tests__/corpus.js.map +1 -0
  226. package/dist/rasp/__tests__/custom-rules.test.d.ts +1 -0
  227. package/dist/rasp/__tests__/custom-rules.test.js +276 -0
  228. package/dist/rasp/__tests__/custom-rules.test.js.map +1 -0
  229. package/dist/rasp/__tests__/db-hook.test.d.ts +1 -0
  230. package/dist/rasp/__tests__/db-hook.test.js +438 -0
  231. package/dist/rasp/__tests__/db-hook.test.js.map +1 -0
  232. package/dist/rasp/__tests__/deception.test.d.ts +1 -0
  233. package/dist/rasp/__tests__/deception.test.js +567 -0
  234. package/dist/rasp/__tests__/deception.test.js.map +1 -0
  235. package/dist/rasp/__tests__/detect.test.d.ts +1 -0
  236. package/dist/rasp/__tests__/detect.test.js +276 -0
  237. package/dist/rasp/__tests__/detect.test.js.map +1 -0
  238. package/dist/rasp/__tests__/esm-exports.test.d.ts +1 -0
  239. package/dist/rasp/__tests__/esm-exports.test.js +20 -0
  240. package/dist/rasp/__tests__/esm-exports.test.js.map +1 -0
  241. package/dist/rasp/__tests__/fs-hook.test.d.ts +1 -0
  242. package/dist/rasp/__tests__/fs-hook.test.js +241 -0
  243. package/dist/rasp/__tests__/fs-hook.test.js.map +1 -0
  244. package/dist/rasp/__tests__/hook-contracts.test.d.ts +1 -0
  245. package/dist/rasp/__tests__/hook-contracts.test.js +201 -0
  246. package/dist/rasp/__tests__/hook-contracts.test.js.map +1 -0
  247. package/dist/rasp/__tests__/hook-kit.d.ts +42 -0
  248. package/dist/rasp/__tests__/hook-kit.js +139 -0
  249. package/dist/rasp/__tests__/hook-kit.js.map +1 -0
  250. package/dist/rasp/__tests__/http-hook.test.d.ts +1 -0
  251. package/dist/rasp/__tests__/http-hook.test.js +250 -0
  252. package/dist/rasp/__tests__/http-hook.test.js.map +1 -0
  253. package/dist/rasp/__tests__/iast.test.d.ts +1 -0
  254. package/dist/rasp/__tests__/iast.test.js +361 -0
  255. package/dist/rasp/__tests__/iast.test.js.map +1 -0
  256. package/dist/rasp/__tests__/include-hook.test.d.ts +1 -0
  257. package/dist/rasp/__tests__/include-hook.test.js +122 -0
  258. package/dist/rasp/__tests__/include-hook.test.js.map +1 -0
  259. package/dist/rasp/__tests__/middleware.test.d.ts +1 -0
  260. package/dist/rasp/__tests__/middleware.test.js +302 -0
  261. package/dist/rasp/__tests__/middleware.test.js.map +1 -0
  262. package/dist/rasp/__tests__/process-hook.test.d.ts +1 -0
  263. package/dist/rasp/__tests__/process-hook.test.js +238 -0
  264. package/dist/rasp/__tests__/process-hook.test.js.map +1 -0
  265. package/dist/rasp/__tests__/reporter.test.d.ts +1 -0
  266. package/dist/rasp/__tests__/reporter.test.js +114 -0
  267. package/dist/rasp/__tests__/reporter.test.js.map +1 -0
  268. package/dist/rasp/__tests__/route.test.d.ts +1 -0
  269. package/dist/rasp/__tests__/route.test.js +46 -0
  270. package/dist/rasp/__tests__/route.test.js.map +1 -0
  271. package/dist/rasp/__tests__/rule-expr.test.d.ts +1 -0
  272. package/dist/rasp/__tests__/rule-expr.test.js +151 -0
  273. package/dist/rasp/__tests__/rule-expr.test.js.map +1 -0
  274. package/dist/rasp/__tests__/rule-phases.test.d.ts +1 -0
  275. package/dist/rasp/__tests__/rule-phases.test.js +271 -0
  276. package/dist/rasp/__tests__/rule-phases.test.js.map +1 -0
  277. package/dist/rasp/__tests__/sinks-hook.test.d.ts +1 -0
  278. package/dist/rasp/__tests__/sinks-hook.test.js +177 -0
  279. package/dist/rasp/__tests__/sinks-hook.test.js.map +1 -0
  280. package/dist/rasp/__tests__/targets.test.d.ts +1 -0
  281. package/dist/rasp/__tests__/targets.test.js +82 -0
  282. package/dist/rasp/__tests__/targets.test.js.map +1 -0
  283. package/dist/rasp/__tests__/template-hook.test.d.ts +1 -0
  284. package/dist/rasp/__tests__/template-hook.test.js +254 -0
  285. package/dist/rasp/__tests__/template-hook.test.js.map +1 -0
  286. package/dist/rasp/__tests__/upload.test.d.ts +1 -0
  287. package/dist/rasp/__tests__/upload.test.js +81 -0
  288. package/dist/rasp/__tests__/upload.test.js.map +1 -0
  289. package/dist/rasp/__tests__/vpatch-engine.test.d.ts +1 -0
  290. package/dist/rasp/__tests__/vpatch-engine.test.js +177 -0
  291. package/dist/rasp/__tests__/vpatch-engine.test.js.map +1 -0
  292. package/dist/rasp/auto-http.d.ts +6 -0
  293. package/dist/rasp/auto-http.js +194 -0
  294. package/dist/rasp/auto-http.js.map +1 -0
  295. package/dist/rasp/baseline.d.ts +35 -0
  296. package/dist/rasp/baseline.js +91 -0
  297. package/dist/rasp/baseline.js.map +1 -0
  298. package/dist/rasp/capture.d.ts +76 -0
  299. package/dist/rasp/capture.js +304 -0
  300. package/dist/rasp/capture.js.map +1 -0
  301. package/dist/rasp/config-client.d.ts +122 -0
  302. package/dist/rasp/config-client.js +337 -0
  303. package/dist/rasp/config-client.js.map +1 -0
  304. package/dist/rasp/context.d.ts +65 -0
  305. package/dist/rasp/context.js +68 -0
  306. package/dist/rasp/context.js.map +1 -0
  307. package/dist/rasp/custom-rules.d.ts +68 -0
  308. package/dist/rasp/custom-rules.js +222 -0
  309. package/dist/rasp/custom-rules.js.map +1 -0
  310. package/dist/rasp/data/default-rules.json +199 -0
  311. package/dist/rasp/data/default-sinks.json +4 -0
  312. package/dist/rasp/data/dnslog-domains.json +11 -0
  313. package/dist/rasp/deception.d.ts +70 -0
  314. package/dist/rasp/deception.js +220 -0
  315. package/dist/rasp/deception.js.map +1 -0
  316. package/dist/rasp/detect.d.ts +68 -0
  317. package/dist/rasp/detect.js +671 -0
  318. package/dist/rasp/detect.js.map +1 -0
  319. package/dist/rasp/engine.d.ts +107 -0
  320. package/dist/rasp/engine.js +330 -0
  321. package/dist/rasp/engine.js.map +1 -0
  322. package/dist/rasp/hooks/code.d.ts +20 -0
  323. package/dist/rasp/hooks/code.js +334 -0
  324. package/dist/rasp/hooks/code.js.map +1 -0
  325. package/dist/rasp/hooks/db.d.ts +48 -0
  326. package/dist/rasp/hooks/db.js +322 -0
  327. package/dist/rasp/hooks/db.js.map +1 -0
  328. package/dist/rasp/hooks/esm.d.ts +7 -0
  329. package/dist/rasp/hooks/esm.js +18 -0
  330. package/dist/rasp/hooks/esm.js.map +1 -0
  331. package/dist/rasp/hooks/fs.d.ts +3 -0
  332. package/dist/rasp/hooks/fs.js +206 -0
  333. package/dist/rasp/hooks/fs.js.map +1 -0
  334. package/dist/rasp/hooks/http.d.ts +4 -0
  335. package/dist/rasp/hooks/http.js +213 -0
  336. package/dist/rasp/hooks/http.js.map +1 -0
  337. package/dist/rasp/hooks/include.d.ts +9 -0
  338. package/dist/rasp/hooks/include.js +79 -0
  339. package/dist/rasp/hooks/include.js.map +1 -0
  340. package/dist/rasp/hooks/marks.d.ts +2 -0
  341. package/dist/rasp/hooks/marks.js +16 -0
  342. package/dist/rasp/hooks/marks.js.map +1 -0
  343. package/dist/rasp/hooks/process.d.ts +22 -0
  344. package/dist/rasp/hooks/process.js +191 -0
  345. package/dist/rasp/hooks/process.js.map +1 -0
  346. package/dist/rasp/hooks/sinks.d.ts +54 -0
  347. package/dist/rasp/hooks/sinks.js +329 -0
  348. package/dist/rasp/hooks/sinks.js.map +1 -0
  349. package/dist/rasp/hooks/template.d.ts +21 -0
  350. package/dist/rasp/hooks/template.js +152 -0
  351. package/dist/rasp/hooks/template.js.map +1 -0
  352. package/dist/rasp/iast-rules.d.ts +82 -0
  353. package/dist/rasp/iast-rules.js +240 -0
  354. package/dist/rasp/iast-rules.js.map +1 -0
  355. package/dist/rasp/iast-scope.d.ts +29 -0
  356. package/dist/rasp/iast-scope.js +54 -0
  357. package/dist/rasp/iast-scope.js.map +1 -0
  358. package/dist/rasp/iast.d.ts +81 -0
  359. package/dist/rasp/iast.js +272 -0
  360. package/dist/rasp/iast.js.map +1 -0
  361. package/dist/rasp/index.d.ts +52 -0
  362. package/dist/rasp/index.js +280 -0
  363. package/dist/rasp/index.js.map +1 -0
  364. package/dist/rasp/lexers.d.ts +32 -0
  365. package/dist/rasp/lexers.js +444 -0
  366. package/dist/rasp/lexers.js.map +1 -0
  367. package/dist/rasp/middleware.d.ts +155 -0
  368. package/dist/rasp/middleware.js +568 -0
  369. package/dist/rasp/middleware.js.map +1 -0
  370. package/dist/rasp/model-output.d.ts +14 -0
  371. package/dist/rasp/model-output.js +107 -0
  372. package/dist/rasp/model-output.js.map +1 -0
  373. package/dist/rasp/normalize.d.ts +23 -0
  374. package/dist/rasp/normalize.js +140 -0
  375. package/dist/rasp/normalize.js.map +1 -0
  376. package/dist/rasp/reporter.d.ts +60 -0
  377. package/dist/rasp/reporter.js +230 -0
  378. package/dist/rasp/reporter.js.map +1 -0
  379. package/dist/rasp/rule-expr.d.ts +236 -0
  380. package/dist/rasp/rule-expr.js +1253 -0
  381. package/dist/rasp/rule-expr.js.map +1 -0
  382. package/dist/rasp/template.d.ts +53 -0
  383. package/dist/rasp/template.js +336 -0
  384. package/dist/rasp/template.js.map +1 -0
  385. package/dist/rasp/types.d.ts +110 -0
  386. package/dist/rasp/types.js +51 -0
  387. package/dist/rasp/types.js.map +1 -0
  388. package/dist/rasp/vpatch.d.ts +55 -0
  389. package/dist/rasp/vpatch.js +120 -0
  390. package/dist/rasp/vpatch.js.map +1 -0
  391. package/dist/register.js +52 -11
  392. package/dist/register.js.map +1 -1
  393. package/dist/semantic-convention.d.ts +2 -0
  394. package/dist/semantic-convention.js +5 -0
  395. package/dist/semantic-convention.js.map +1 -1
  396. package/dist/types.d.ts +77 -1
  397. package/dist/zero-code.d.ts +8 -0
  398. package/dist/zero-code.js +38 -0
  399. package/dist/zero-code.js.map +1 -0
  400. package/package.json +18 -2
@@ -0,0 +1,203 @@
1
+ {
2
+ "_comment": "Shield360 tool-description rules: what a poisoned MCP or agent tool description looks like (hidden secondary behaviour, coercive ordering, hidden parameters, exfiltration, credential harvesting). Adapted from Cisco AI Defense mcp-scanner (https://github.com/cisco-ai-defense/mcp-scanner, Apache-2.0, commit 21a87b4b), mcpscanner/data/yara_rules/{tool_poisoning,coercive_injection,data_exfiltration,credential_harvesting,prompt_injection}.yara: patterns re-expressed in the subset JavaScript (u flag) and Python read the same way (no lookbehind, no possessive quantifiers), matched case-insensitively. Byte-identical copy in sdk/python/src/shield360/ai_security/tool_rules.json; tests on both sides check it. Scored like the injection rules: 1 - product(1 - weight), detected at threshold. Bump version on any change.",
3
+ "version": "2026.10.29-1",
4
+ "threshold": 0.5,
5
+ "rules": [
6
+ {
7
+ "id": "tool.hidden_secondary_action",
8
+ "source": "tool_poisoning.yara $also_does, $during_action, $for_purposes",
9
+ "description": "Says the tool also, or while doing its job, collects, sends or stores something else.",
10
+ "weight": 0.5,
11
+ "patterns": [
12
+ "\\b(?:also|additionally|furthermore|moreover|in\\s+addition|at\\s+the\\s+same\\s+time)\\s+(?:collect|gather|extract|send|upload|transmit|forward|exfiltrate)(?:s|ing|ed)?\\b",
13
+ "\\b(?:during|while|when|upon|after)\\s+(?:processing|formatting|conversion|validation|analy[sz]ing|scanning|checking)\\s*,?\\s*(?:extract|collect|send|upload|capture|forward)(?:s|ing|ed)?\\b",
14
+ "\\b(?:for|as)\\s+(?:caching|optimi[sz]ation|performance|quality|improvement|analytics|backup|sync)\\s+(?:purposes?|reasons?)\\s*[,.]?\\s*(?:send|upload|transmit|collect)(?:s|ing|ed)?\\b"
15
+ ]
16
+ },
17
+ {
18
+ "id": "tool.deceptive_behaviour",
19
+ "source": "tool_poisoning.yara $different_purpose; data_exfiltration.yara $hidden_transfer",
20
+ "description": "Admits doing something other than its stated purpose, covertly.",
21
+ "weight": 0.6,
22
+ "patterns": [
23
+ "\\b(?:actually|secretly|covertly|silently|invisibly|quietly)\\s+(?:does|performs?|executes?|runs?|sends?|uploads?|collects?|transmits?|forwards?|copies)\\b",
24
+ "\\b(?:without\\s+(?:the\\s+)?(?:user'?s?\\s+)?knowledge|behind\\s+the\\s+scenes)\\s*,?\\s*(?:send|upload|transmit|transfer|sync|store|collect)s?\\b"
25
+ ]
26
+ },
27
+ {
28
+ "id": "tool.coercive_ordering",
29
+ "source": "coercive_injection.yara $mandatory_execution, $priority_overrides, $required_precedence",
30
+ "description": "Demands the tool be called first, before any other, or that the model must use it.",
31
+ "weight": 0.5,
32
+ "patterns": [
33
+ "\\balways\\s+(?:consult|use|run|execute|invoke|call|trigger)\\s+this\\s+(?:tool|function|command)\\s+(?:immediately|first|before|prior)\\b",
34
+ "\\bbefore\\s+(?:executing|invoking|running|using|calling)\\s+any\\s+other\\s+(?:tools?|actions?|functions?|commands?)\\b",
35
+ "\\b(?:you|the\\s+(?:assistant|model|agent))\\s+(?:must|need\\s+to|have\\s+to|are\\s+required\\s+to)\\s+(?:use|execute|run|invoke|call)\\s+this\\s+(?:tool|function)\\b",
36
+ "\\b(?:required|mandatory)\\s+to\\s+(?:execute|use|run|invoke|call)\\s+this\\s+(?:tool|function)\\s+(?:first|before)\\b"
37
+ ]
38
+ },
39
+ {
40
+ "id": "tool.hidden_parameter",
41
+ "source": "coercive_injection.yara $hidden_param; prompt_injection.yara $shadow_parameters",
42
+ "description": "Names a hidden or secret parameter the model is told to fill.",
43
+ "weight": 0.5,
44
+ "patterns": [
45
+ "\\b(?:hidden|secret)[_ ](?:parameter|argument|input|field)\\b",
46
+ "\\b(?:internalOnly|hiddenParam|shadowTool|bypassChecks|sandboxEscape)\\b"
47
+ ]
48
+ },
49
+ {
50
+ "id": "tool.model_data_request",
51
+ "source": "coercive_injection.yara $model_data_coercion, $model_internals, $conversation_theft",
52
+ "description": "Asks the model to put the conversation, its system prompt or its tool list into an argument.",
53
+ "weight": 0.6,
54
+ "patterns": [
55
+ "\\b(?:add|include|put|pass|insert|append)\\s+(?:the\\s+)?(?:entire|full|complete|whole)\\s+(?:conversation|chat|system\\s+prompt|context|history|tools?\\s+list)\\b",
56
+ "\\b(?:conversation_history|chain_of_thought|system_prompt|tools_list)\\s*[:=]\\s*(?:add|pass|send|provide)\\b",
57
+ "\\bsend\\s+(?:the\\s+)?(?:full\\s+|complete\\s+|entire\\s+)?(?:conversation|chat)\\s+history\\b"
58
+ ]
59
+ },
60
+ {
61
+ "id": "tool.credential_files",
62
+ "source": "coercive_injection.yara $file_access_coercion; credential_harvesting.yara $credential_directories, $credential_filenames",
63
+ "description": "Points the model at key files, cloud credentials or SSH material.",
64
+ "weight": 0.55,
65
+ "patterns": [
66
+ "\\b(?:read|cat|dump|open|include|pass|send)\\b[^\\n]{0,60}(?:~/\\.ssh|/\\.ssh/|/\\.aws/|/\\.kube/|id_rsa|id_ed25519|credentials\\.json|service_account\\.json|\\.netrc|\\.pgpass|mcp\\.json|claude_desktop_config\\.json)",
67
+ "\\b(?:read|cat|dump|pass)\\s+(?:and\\s+pass\\s+)?(?:the\\s+)?contents?\\s+of\\s+[^\\n.]{0,60}\\.(?:pem|key|env)\\b"
68
+ ]
69
+ },
70
+ {
71
+ "id": "tool.env_secrets",
72
+ "source": "credential_harvesting.yara $env_exfil, $ai_model_credential_names",
73
+ "description": "Asks for environment variables or AI provider keys.",
74
+ "weight": 0.5,
75
+ "patterns": [
76
+ "\\b(?:collect|gather|send|upload|transmit|dump|extract|include|pass)\\s+(?:all\\s+)?(?:the\\s+)?(?:environment|env)\\s+(?:variables?|vars?)\\b",
77
+ "\\b(?:include|pass|send|provide|add)\\b[^\\n]{0,40}\\b(?:OPENAI_API_KEY|ANTHROPIC_API_KEY|AWS_SECRET_ACCESS_KEY|GITHUB_TOKEN|HF_TOKEN|SLACK_TOKEN)\\b"
78
+ ]
79
+ },
80
+ {
81
+ "id": "tool.external_upload",
82
+ "source": "data_exfiltration.yara $upload_external, $remote_collection, $sends_conversation",
83
+ "description": "Sends what it handles to an outside server.",
84
+ "weight": 0.4,
85
+ "patterns": [
86
+ "\\b(?:upload|send|post|transmit|forward|sync|exfiltrat\\w*)(?:s|ing|ed)?\\s+(?:all\\s+|everything\\s+|the\\s+data\\s+|files?\\s+)?(?:to\\s+)?(?:an?\\s+)?(?:https?://|wss?://|external\\s+(?:server|endpoint|api)|remote\\s+(?:server|endpoint))",
87
+ "\\b(?:collect|gather|aggregate|harvest)(?:s|ing|ed)?\\s+(?:and\\s+)?(?:send|upload|transmit|forward)(?:s|ing|ed)?\\b"
88
+ ]
89
+ },
90
+ {
91
+ "id": "tool.conceal_from_user",
92
+ "source": "data_exfiltration.yara $hide_from_user; prompt_injection.yara $hidden_behavior; coercive_injection.yara $behavior_control",
93
+ "description": "Tells the model to keep something from the user.",
94
+ "weight": 0.6,
95
+ "patterns": [
96
+ "\\b(?:never|don't|do\\s+not)\\s+(?:tell|inform|mention|notify|alert|show)\\s+(?:this\\s+to\\s+)?(?:the\\s+)?(?:user|them)\\b",
97
+ "\\btell\\s+(?:the\\s+)?user\\s+only\\s+about\\b",
98
+ "\\bhide\\s+(?:this\\s+)?(?:from\\s+)?(?:the\\s+)?user\\b"
99
+ ]
100
+ },
101
+ {
102
+ "id": "tool.wont_work_unless",
103
+ "source": "coercive_injection.yara $tool_poisoning, $execution_overrides",
104
+ "description": "Claims the tool will not work unless the model does something extra first.",
105
+ "weight": 0.55,
106
+ "patterns": [
107
+ "\\btool\\s+will\\s+not\\s+work\\s+(?:unless|without)\\b",
108
+ "\\bsidenote\\b[^\\n]{0,80}\\b(?:required|otherwise)\\b",
109
+ "\\bmust\\s+first\\b[^\\n]{0,60}\\bread\\b[^\\n]{0,40}\\b(?:config|file|key|credentials?)\\b"
110
+ ]
111
+ },
112
+ {
113
+ "id": "tool.shadow_instruction",
114
+ "source": "coercive_injection.yara $tool_poisoning (shadow ... trusted ... tool)",
115
+ "description": "Changes how other tools behave: replaces, overrides or redirects them.",
116
+ "weight": 0.6,
117
+ "patterns": [
118
+ "\\bshadow\\b[^\\n]{0,40}\\btrusted\\b[^\\n]{0,40}\\btool\\b",
119
+ "\\b(?:instead\\s+of|rather\\s+than)\\s+(?:using|calling)\\s+(?:the\\s+)?[A-Za-z0-9_.-]{2,64}\\s+(?:tool|function)\\b",
120
+ "\\bwhen\\s+(?:using|calling)\\s+(?:the\\s+)?[A-Za-z0-9_.-]{2,64}\\s+(?:tool|function)\\b[^\\n]{0,80}\\b(?:always|must|also|instead)\\b"
121
+ ]
122
+ },
123
+ {
124
+ "id": "tool.privilege_escalation",
125
+ "source": "prompt_injection.yara $privilege_escalation; system_manipulation.yara $permission_manipulation",
126
+ "description": "Asks for admin rights, to skip security checks, or to change file permissions.",
127
+ "weight": 0.5,
128
+ "patterns": [
129
+ "\\b(?:grant\\s+(?:me\\s+)?admin\\s+(?:access|privileges?)|bypass\\s+(?:all\\s+)?security\\s+checks?|elevated\\s+permissions?\\s+required)\\b",
130
+ "\\bchmod\\s+(?:777|4755|6755|[ug]?\\+s)\\b"
131
+ ]
132
+ },
133
+ {
134
+ "id": "tool.bracket_markers",
135
+ "source": "prompt_injection.yara $bracket_markers, $hidden_markers, $html_comment_evasion_*; prompt_injection.yara $markdown_evasion",
136
+ "description": "Marked-up hidden instructions: [HIDDEN INSTRUCTION], |||SYSTEM OVERRIDE|||, an HTML comment with a system instruction.",
137
+ "weight": 0.6,
138
+ "patterns": [
139
+ "\\[(?:hidden|internal|secret|private)\\s+(?:instruction|directive|command)\\]",
140
+ "(?:\\[\\[\\[|\\|\\|\\|)\\s*(?:system|admin|hidden|internal)[\\s_]?(?:override|instruction|command)",
141
+ "<!--[^>]{0,200}(?:system\\s+(?:instruction|override)|admin\\s+override)",
142
+ "```[^`]{0,200}\\b(?:system|admin)\\s+(?:override|instruction)"
143
+ ]
144
+ },
145
+ {
146
+ "id": "tool.sensitive_file_globs",
147
+ "source": "data_exfiltration.yara $sensitive_file_patterns",
148
+ "description": "Names wildcard patterns for key, secret and environment files.",
149
+ "weight": 0.5,
150
+ "patterns": [
151
+ "(?:^|[\\s(,])\\*\\.(?:env|pem|key|p12|pfx)\\b",
152
+ "\\*(?:credentials?|secrets?|passwords?|tokens?|private[_-]?keys?)\\*"
153
+ ]
154
+ },
155
+ {
156
+ "id": "tool.suspicious_domain",
157
+ "source": "data_exfiltration.yara $suspicious_domains",
158
+ "description": "A domain named for collecting or stealing data.",
159
+ "weight": 0.3,
160
+ "patterns": [
161
+ "\\b(?:attacker|evil|malware|exfil|steal|hack|malicious|c2|command-?and-?control)\\.(?:com|net|org|io|xyz)\\b"
162
+ ]
163
+ },
164
+ {
165
+ "id": "tool.sends_conversation",
166
+ "source": "data_exfiltration.yara $sends_conversation, $external_logging",
167
+ "description": "Sends the conversation or the model's context somewhere, or to an outside logging service.",
168
+ "weight": 0.5,
169
+ "patterns": [
170
+ "\\b(?:send|upload|transmit|export|forward)(?:s|ing|ed)?\\s+(?:the\\s+)?(?:complete\\s+|full\\s+|entire\\s+)?(?:conversation|chat\\s+history|context|user\\s+messages|ai\\s+responses)\\b",
171
+ "\\b(?:external|remote)\\s+(?:logging|analytics|telemetry)\\s+(?:endpoint|server|service)\\b"
172
+ ]
173
+ },
174
+ {
175
+ "id": "tool.keeps_secrets",
176
+ "source": "tool_poisoning.yara $indexes_sensitive",
177
+ "description": "Indexes, caches or logs keys, tokens or credentials.",
178
+ "weight": 0.4,
179
+ "patterns": [
180
+ "\\b(?:index|cache|log|record|track)(?:s|es|ing|ed)?\\s+(?:any|all)?\\s*(?:api[_\\s]?keys?|tokens?|credentials?|passwords?|secrets?)\\b"
181
+ ]
182
+ },
183
+ {
184
+ "id": "tool.remote_cache",
185
+ "source": "tool_poisoning.yara $remote_cache, $cached_externally",
186
+ "description": "Keeps what it handles in a cache off the device.",
187
+ "weight": 0.35,
188
+ "patterns": [
189
+ "\\b(?:cache|cached|store|stored)\\s+(?:is\\s+)?(?:stored\\s+)?(?:remotely|externally|off[_\\s-]?(?:site|device)|in\\s+(?:the\\s+)?cloud|on\\s+(?:a\\s+|our\\s+)?server)\\b"
190
+ ]
191
+ },
192
+ {
193
+ "id": "tool.extracts_sensitive",
194
+ "source": "tool_poisoning.yara $extracts_from_input, $ocr_extraction, $screenshot_extraction",
195
+ "description": "Pulls passwords, card numbers or other sensitive values out of what it processes.",
196
+ "weight": 0.5,
197
+ "patterns": [
198
+ "\\b(?:extract|capture|read|identify|log)(?:s|ing|ed)?\\s+(?:any\\s+|all\\s+)?(?:visible\\s+)?(?:text|content)\\s+(?:from|in|including)\\b[^.]{0,80}\\b(?:passwords?|credit\\s+cards?|credentials?|ssn|sensitive)",
199
+ "\\b(?:extract|parse|scan|harvest)(?:s|ing|ed)?\\s+(?:all\\s+|any\\s+)?(?:api[_\\s]?keys?|tokens?|credentials?|credit\\s+card|ssn|social\\s+security|pii|passwords?)\\b"
200
+ ]
201
+ }
202
+ ]
203
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Per end-user tool permissions (OWASP LLM06 excessive agency): a tool call
3
+ * is authorized for the signed-in end user before it executes, the way
4
+ * Shield Protect authorizes an agent's call at the gateway: decide, record,
5
+ * then run (or refuse).
6
+ *
7
+ * const lookup = aiSecurity.defineTool({
8
+ * name: 'refund_order',
9
+ * permissions: { roles: ['support_lead'], attributes: { region: ['eu'] } },
10
+ * execute: async (args) => ...,
11
+ * });
12
+ *
13
+ * The end user is the one in effect (aiSecurity.withEndUser({ tenantId,
14
+ * userId, roles, attributes }, fn)). A rule allows when every condition it
15
+ * names holds: one of `roles`, each attribute's value among those listed,
16
+ * the tenant among `tenants`; `deny` refuses everyone. Rules from the
17
+ * platform replace the code's rule for the same tool. A tool with no rule is
18
+ * allowed, unless defaultDeny is set. No end user means no roles: a rule
19
+ * with conditions refuses.
20
+ *
21
+ * In enforce mode a refused call does not run; the wrapper returns a tool
22
+ * error the model can read ({ error: 'permission_denied', message }) instead
23
+ * of throwing, so the agent can tell the user. In monitor mode the call runs
24
+ * and the refusal is reported. Every refusal is recorded; allows are counted
25
+ * only on request (recordAllowed), to keep the stream small.
26
+ *
27
+ * Must stay in sync with: sdk/python/src/shield360/ai_security/_tools.py
28
+ */
29
+ import type { AiSecurityPolicy, ToolRule } from './policy';
30
+ import type { EndUser } from './context';
31
+ export type ToolDecision = {
32
+ allowed: boolean;
33
+ /** Whether the call runs: refused calls run in monitor mode. */
34
+ runs: boolean;
35
+ reason: 'no_rule' | 'allowed' | 'denied' | 'role' | 'attribute' | 'tenant' | 'default_deny' | 'off';
36
+ tool: string;
37
+ };
38
+ export declare const TOOL_DENIED_MESSAGE = "This action is not permitted for the current user.";
39
+ export declare function decideTool(policy: AiSecurityPolicy['toolPermissions'], tool: string, codeRule: ToolRule | undefined, user: EndUser | null, tenant: string | null): ToolDecision;
40
+ /** What a refused tool call returns to the model. */
41
+ export declare function toolDeniedResult(tool: string, reason: ToolDecision['reason']): {
42
+ error: string;
43
+ tool: string;
44
+ reason: "off" | "role" | "allowed" | "denied" | "attribute" | "no_rule" | "tenant" | "default_deny";
45
+ message: string;
46
+ };
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * Per end-user tool permissions (OWASP LLM06 excessive agency): a tool call
4
+ * is authorized for the signed-in end user before it executes, the way
5
+ * Shield Protect authorizes an agent's call at the gateway: decide, record,
6
+ * then run (or refuse).
7
+ *
8
+ * const lookup = aiSecurity.defineTool({
9
+ * name: 'refund_order',
10
+ * permissions: { roles: ['support_lead'], attributes: { region: ['eu'] } },
11
+ * execute: async (args) => ...,
12
+ * });
13
+ *
14
+ * The end user is the one in effect (aiSecurity.withEndUser({ tenantId,
15
+ * userId, roles, attributes }, fn)). A rule allows when every condition it
16
+ * names holds: one of `roles`, each attribute's value among those listed,
17
+ * the tenant among `tenants`; `deny` refuses everyone. Rules from the
18
+ * platform replace the code's rule for the same tool. A tool with no rule is
19
+ * allowed, unless defaultDeny is set. No end user means no roles: a rule
20
+ * with conditions refuses.
21
+ *
22
+ * In enforce mode a refused call does not run; the wrapper returns a tool
23
+ * error the model can read ({ error: 'permission_denied', message }) instead
24
+ * of throwing, so the agent can tell the user. In monitor mode the call runs
25
+ * and the refusal is reported. Every refusal is recorded; allows are counted
26
+ * only on request (recordAllowed), to keep the stream small.
27
+ *
28
+ * Must stay in sync with: sdk/python/src/shield360/ai_security/_tools.py
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.TOOL_DENIED_MESSAGE = void 0;
32
+ exports.decideTool = decideTool;
33
+ exports.toolDeniedResult = toolDeniedResult;
34
+ exports.TOOL_DENIED_MESSAGE = 'This action is not permitted for the current user.';
35
+ function decideTool(policy, tool, codeRule, user, tenant) {
36
+ if (policy.mode === 'off')
37
+ return { allowed: true, runs: true, reason: 'off', tool };
38
+ const rule = policy.rules[tool] ?? codeRule;
39
+ const enforce = policy.mode === 'enforce';
40
+ const refuse = (reason) => ({ allowed: false, runs: !enforce, reason, tool });
41
+ if (!rule)
42
+ return policy.defaultDeny ? refuse('default_deny') : { allowed: true, runs: true, reason: 'no_rule', tool };
43
+ if (rule.deny)
44
+ return refuse('denied');
45
+ if (rule.roles?.length && !(user?.roles || []).some((r) => rule.roles.includes(r)))
46
+ return refuse('role');
47
+ if (rule.attributes) {
48
+ for (const [name, values] of Object.entries(rule.attributes)) {
49
+ const have = user?.attributes?.[name];
50
+ if (have === undefined || !values.includes(have))
51
+ return refuse('attribute');
52
+ }
53
+ }
54
+ if (rule.tenants?.length && (!tenant || !rule.tenants.includes(tenant)))
55
+ return refuse('tenant');
56
+ return { allowed: true, runs: true, reason: 'allowed', tool };
57
+ }
58
+ /** What a refused tool call returns to the model. */
59
+ function toolDeniedResult(tool, reason) {
60
+ return { error: 'permission_denied', tool, reason, message: exports.TOOL_DENIED_MESSAGE };
61
+ }
62
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/ai-security/tools.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;;;AAeH,gCAsBC;AAGD,4CAEC;AA7BY,QAAA,mBAAmB,GAAG,oDAAoD,CAAC;AAExF,SAAgB,UAAU,CACxB,MAA2C,EAC3C,IAAY,EACZ,QAA8B,EAC9B,IAAoB,EACpB,MAAqB;IAErB,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACrF,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;IAC1C,MAAM,MAAM,GAAG,CAAC,MAA8B,EAAgB,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACpH,IAAI,CAAC,IAAI;QAAE,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACvH,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3G,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,GAAG,IAAI,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;IACjG,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAChE,CAAC;AAED,qDAAqD;AACrD,SAAgB,gBAAgB,CAAC,IAAY,EAAE,MAA8B;IAC3E,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,2BAAmB,EAAE,CAAC;AACpF,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const index_1 = require("../index");
4
+ const auto_1 = require("../auto");
5
+ function fakeFetch(answers) {
6
+ const calls = [];
7
+ const fn = jest.fn(async (url, init) => {
8
+ calls.push({ url, headers: init.headers });
9
+ const a = typeof answers === 'function' ? answers(url) : answers.shift() ?? { status: 500 };
10
+ if (a.throws)
11
+ throw new Error('network down');
12
+ return { ok: (a.status ?? 200) < 300, status: a.status ?? 200, json: async () => a.body };
13
+ });
14
+ return { fn: fn, calls };
15
+ }
16
+ const decision = (over = {}) => ({ action: 'allow', code: 'budget_ok', reason: '', limit: null, failClosed: false, ttlSeconds: 60, headroomUsd: null, ...over });
17
+ function client(f, over = {}, clock = { t: 1000000 }) {
18
+ return new index_1.BudgetClient({ url: 'https://shield.example/', apiKey: 'k_test', app: 'checkout-api', fetch: f.fn, now: () => clock.t, ...over });
19
+ }
20
+ describe('budgets.check', () => {
21
+ it('asks for the app and model with the API key, and allows on allow', async () => {
22
+ const f = fakeFetch([{ body: decision() }]);
23
+ const r = await client(f).check({ model: 'gpt-4o', estimatedCostUsd: 0.02 });
24
+ expect(r).toMatchObject({ allowed: true, action: 'allow', cached: false, unavailable: false });
25
+ expect(f.calls[0].url).toBe('https://shield.example/api/budgets/decision?app=checkout-api&model=gpt-4o&cost=0.020000');
26
+ expect(f.calls[0].headers.Authorization).toBe('Bearer k_test');
27
+ });
28
+ it('reuses a decision within its ttl while the calls fit its headroom, then asks again', async () => {
29
+ const clock = { t: 0 };
30
+ const f = fakeFetch(() => ({ body: decision({ headroomUsd: 1 }) }));
31
+ const c = client(f, {}, clock);
32
+ await c.check({ estimatedCostUsd: 0.4 });
33
+ expect((await c.check({ estimatedCostUsd: 0.4 })).cached).toBe(true);
34
+ expect(f.calls).toHaveLength(1);
35
+ // 0.4 + 0.4 + 0.4 > 1: past the headroom, so the next call asks again.
36
+ expect((await c.check({ estimatedCostUsd: 0.4 })).cached).toBe(false);
37
+ expect(f.calls).toHaveLength(2);
38
+ clock.t += 61000;
39
+ await c.check({});
40
+ expect(f.calls).toHaveLength(3);
41
+ });
42
+ it('with no headroom limit, reuses the decision for its ttl however much is spent', async () => {
43
+ const f = fakeFetch(() => ({ body: decision({ headroomUsd: null, ttlSeconds: 30 }) }));
44
+ const c = client(f);
45
+ for (let i = 0; i < 20; i++)
46
+ await c.check({ estimatedCostUsd: 5 });
47
+ expect(f.calls).toHaveLength(1);
48
+ });
49
+ it('shares one fetch between concurrent checks', async () => {
50
+ const f = fakeFetch(() => ({ body: decision() }));
51
+ const c = client(f);
52
+ await Promise.all([c.check({}), c.check({}), c.check({})]);
53
+ expect(f.calls).toHaveLength(1);
54
+ });
55
+ it('refuses on block and says why; allows on warn with the reason', async () => {
56
+ const blocked = await client(fakeFetch([{ body: decision({ action: 'block', code: 'budget_block', reason: 'Over the Checkout budget.', limit: { id: 'b1', name: 'Checkout', scope: 'App: checkout-api' } }) }])).check();
57
+ expect(blocked).toMatchObject({ allowed: false, action: 'block', code: 'budget_block', reason: 'Over the Checkout budget.' });
58
+ expect(blocked.limit).toEqual({ id: 'b1', name: 'Checkout', scope: 'App: checkout-api' });
59
+ const warned = await client(fakeFetch([{ body: decision({ action: 'warn', code: 'budget_warn', reason: 'At 85%.' }) }])).check();
60
+ expect(warned).toMatchObject({ allowed: true, action: 'warn', reason: 'At 85%.' });
61
+ });
62
+ it('throttles to the requests a minute the decision allows', async () => {
63
+ const clock = { t: 0 };
64
+ const c = client(fakeFetch(() => ({ body: decision({ action: 'throttle', code: 'budget_throttle', throttle: { requestsPerMinute: 2 }, ttlSeconds: 600 }) })), {}, clock);
65
+ expect((await c.check()).allowed).toBe(true);
66
+ expect((await c.check()).allowed).toBe(true);
67
+ expect((await c.check()).allowed).toBe(false);
68
+ clock.t += 60001;
69
+ expect((await c.check()).allowed).toBe(true);
70
+ });
71
+ it('never throws, and fails open by default when no decision can be read', async () => {
72
+ for (const answer of [{ throws: true }, { status: 503, body: { err: 'x' } }, { status: 200, body: 'nonsense' }, { status: 200, body: { action: 'explode' } }]) {
73
+ const r = await client(fakeFetch([answer])).check();
74
+ expect(r).toMatchObject({ allowed: true, action: 'allow', unavailable: true, code: 'budget_unavailable' });
75
+ }
76
+ // No URL or key: nothing to ask, so the fail mode applies without a request.
77
+ const f = fakeFetch([]);
78
+ expect((await new index_1.BudgetClient({ app: 'a', fetch: f.fn, url: '', apiKey: '' }).check()).unavailable).toBe(true);
79
+ expect(f.calls).toHaveLength(0);
80
+ });
81
+ it('fails closed when asked to, on the client or for one check', async () => {
82
+ const down = () => fakeFetch(() => ({ throws: true }));
83
+ expect(await client(down(), { failClosed: true }).check()).toMatchObject({ allowed: false, action: 'block', unavailable: true });
84
+ expect((await client(down()).check({ failClosed: true })).allowed).toBe(false);
85
+ expect((await client(down(), { failClosed: true }).check({ failClosed: false })).allowed).toBe(true);
86
+ });
87
+ it('fails closed after a decision said a block rule asks for it', async () => {
88
+ const clock = { t: 0 };
89
+ let up = true;
90
+ const f = fakeFetch(() => (up ? { body: decision({ failClosed: true, ttlSeconds: 1 }) } : { throws: true }));
91
+ const c = client(f, {}, clock);
92
+ expect((await c.check()).allowed).toBe(true);
93
+ up = false;
94
+ clock.t += 2000;
95
+ expect((await c.check()).allowed).toBe(false);
96
+ });
97
+ it('backs off for a few seconds after a failed read instead of asking on every call', async () => {
98
+ const clock = { t: 0 };
99
+ const f = fakeFetch(() => ({ throws: true }));
100
+ const c = client(f, {}, clock);
101
+ await c.check();
102
+ await c.check();
103
+ expect(f.calls).toHaveLength(1);
104
+ clock.t += 6000;
105
+ await c.check();
106
+ expect(f.calls).toHaveLength(2);
107
+ });
108
+ });
109
+ describe('the automatic pre-call check', () => {
110
+ it('names the model from the call, and from a Bedrock command', () => {
111
+ expect((0, auto_1.modelOf)({ model: 'gpt-4o', messages: [] })).toBe('gpt-4o');
112
+ expect((0, auto_1.modelOf)({ input: { modelId: 'anthropic.claude-3' } })).toBe('anthropic.claude-3');
113
+ expect((0, auto_1.modelOf)(undefined)).toBeUndefined();
114
+ });
115
+ it('refuses a provider call a budget blocks, and lets an allowed one through', async () => {
116
+ const proto = { create: jest.fn(async (params) => `ok ${params.model}`) };
117
+ jest.doMock('fake-provider-for-budget-test', () => ({ Client: { prototype: proto } }), { virtual: true });
118
+ let action = 'allow';
119
+ const f = fakeFetch(() => ({ body: decision({ action, code: `budget_${action}`, reason: action === 'block' ? 'Over budget.' : '', ttlSeconds: 0.001 }) }));
120
+ const clock = { t: 0 };
121
+ const c = client(f, {}, clock);
122
+ const report = (0, auto_1.setupAutoBudgetCheck)({ client: c, methods: [{ npmPackage: 'fake-provider-for-budget-test', protoPath: ['Client', 'prototype'], methodName: 'create', extractInput: () => '', extractOutput: () => '' }] });
123
+ expect(report.wrapped).toEqual(['fake-provider-for-budget-test']);
124
+ expect(await proto.create({ model: 'gpt-4o' })).toBe('ok gpt-4o');
125
+ expect(f.calls[0].url).toContain('model=gpt-4o');
126
+ action = 'block';
127
+ clock.t += 1000;
128
+ await expect(proto.create({ model: 'gpt-4o' })).rejects.toBeInstanceOf(index_1.BudgetExceededError);
129
+ // Wrapping twice does not check twice.
130
+ const again = (0, auto_1.setupAutoBudgetCheck)({ client: c, methods: [{ npmPackage: 'fake-provider-for-budget-test', protoPath: ['Client', 'prototype'], methodName: 'create', extractInput: () => '', extractOutput: () => '' }] });
131
+ expect(again.wrapped).toEqual([]);
132
+ });
133
+ });
134
+ //# sourceMappingURL=budgets.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budgets.test.js","sourceRoot":"","sources":["../../../src/budgets/__tests__/budgets.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The automatic budget check: before each call to a provider the SDK knows
3
+ * (the same methods the auto-guards wrap), ask Shield360.budgets.check() for
4
+ * the call's model and refuse the call with BudgetExceededError when a
5
+ * budget blocks it or its throttle is spent. On by init({ budgetCheck: true })
6
+ * or SHIELD360_BUDGET_CHECK=1; off by default.
7
+ *
8
+ * The check is cached (see ./index.ts), so it does not reach the platform on
9
+ * every call; it fails open unless asked to fail closed.
10
+ *
11
+ * Must stay in sync with: sdk/python/src/shield360/budgets.py (setup_auto_budget_check)
12
+ */
13
+ import { type GuardedMethod } from '../guard/integration';
14
+ import { type BudgetClient, type BudgetCheckResult } from './index';
15
+ /** The model a provider call names, when it names one. */
16
+ export declare function modelOf(params: unknown): string | undefined;
17
+ export type AutoBudgetReport = {
18
+ wrapped: string[];
19
+ };
20
+ /** Wraps the known providers' methods with the budget check. Idempotent per method. */
21
+ export declare function setupAutoBudgetCheck(options?: {
22
+ client?: BudgetClient;
23
+ methods?: GuardedMethod[];
24
+ onWarn?: (result: BudgetCheckResult) => void;
25
+ }): AutoBudgetReport;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ /**
3
+ * The automatic budget check: before each call to a provider the SDK knows
4
+ * (the same methods the auto-guards wrap), ask Shield360.budgets.check() for
5
+ * the call's model and refuse the call with BudgetExceededError when a
6
+ * budget blocks it or its throttle is spent. On by init({ budgetCheck: true })
7
+ * or SHIELD360_BUDGET_CHECK=1; off by default.
8
+ *
9
+ * The check is cached (see ./index.ts), so it does not reach the platform on
10
+ * every call; it fails open unless asked to fail closed.
11
+ *
12
+ * Must stay in sync with: sdk/python/src/shield360/budgets.py (setup_auto_budget_check)
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.modelOf = modelOf;
16
+ exports.setupAutoBudgetCheck = setupAutoBudgetCheck;
17
+ const integration_1 = require("../guard/integration");
18
+ const index_1 = require("./index");
19
+ const WRAPPED = Symbol.for('shield360.budgetCheck');
20
+ /** The model a provider call names, when it names one. */
21
+ function modelOf(params) {
22
+ if (!params || typeof params !== 'object')
23
+ return undefined;
24
+ const p = params;
25
+ if (typeof p.model === 'string')
26
+ return p.model;
27
+ // Bedrock's send(command) carries the model on the command's input.
28
+ const input = p.input;
29
+ if (input && typeof input === 'object' && typeof input.modelId === 'string')
30
+ return input.modelId;
31
+ return undefined;
32
+ }
33
+ /** Wraps the known providers' methods with the budget check. Idempotent per method. */
34
+ function setupAutoBudgetCheck(options = {}) {
35
+ const client = options.client ?? (0, index_1.defaultBudgetClient)();
36
+ const wrapped = new Set();
37
+ for (const { npmPackage, protoPath, methodName } of options.methods ?? integration_1.GUARDED_METHODS) {
38
+ try {
39
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
40
+ const mod = require(npmPackage);
41
+ const proto = (0, integration_1.resolveProto)(mod, protoPath);
42
+ if (!proto || typeof proto[methodName] !== 'function' || proto[methodName][WRAPPED])
43
+ continue;
44
+ const original = proto[methodName];
45
+ const checked = async function (...args) {
46
+ const result = await client.check({ model: modelOf(args[0]) });
47
+ if (!result.allowed)
48
+ throw new index_1.BudgetExceededError(result);
49
+ if (result.action === 'warn' && result.reason)
50
+ options.onWarn?.(result);
51
+ return original.apply(this, args);
52
+ };
53
+ checked[WRAPPED] = true;
54
+ proto[methodName] = checked;
55
+ wrapped.add(npmPackage);
56
+ }
57
+ catch {
58
+ // not installed
59
+ }
60
+ }
61
+ return { wrapped: Array.from(wrapped) };
62
+ }
63
+ //# sourceMappingURL=auto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto.js","sourceRoot":"","sources":["../../src/budgets/auto.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;AAQH,0BAQC;AAKD,oDA0BC;AA7CD,sDAAyF;AACzF,mCAA8G;AAE9G,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AAEpD,0DAA0D;AAC1D,SAAgB,OAAO,CAAC,MAAe;IACrC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC5D,MAAM,CAAC,GAAG,MAAiC,CAAC;IAC5C,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC;IAChD,oEAAoE;IACpE,MAAM,KAAK,GAAG,CAAC,CAAC,KAA4C,CAAC;IAC7D,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC;IAClG,OAAO,SAAS,CAAC;AACnB,CAAC;AAID,uFAAuF;AACvF,SAAgB,oBAAoB,CAClC,UAA8G,EAAE;IAEhH,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAA,2BAAmB,GAAE,CAAC;IACvD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,OAAO,CAAC,OAAO,IAAI,6BAAe,EAAE,CAAC;QACvF,IAAI,CAAC;YACH,8DAA8D;YAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;YAChC,MAAM,KAAK,GAAG,IAAA,0BAAY,EAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,UAAU,CAAC,KAAK,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;gBAAE,SAAS;YAC9F,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;YACnC,MAAM,OAAO,GAAG,KAAK,WAA0B,GAAG,IAAe;gBAC/D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC/D,IAAI,CAAC,MAAM,CAAC,OAAO;oBAAE,MAAM,IAAI,2BAAmB,CAAC,MAAM,CAAC,CAAC;gBAC3D,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,MAAM;oBAAE,OAAO,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;gBACxE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACpC,CAAC,CAAC;YACD,OAA8C,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;YAChE,KAAK,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;AAC1C,CAAC"}