@cdot65/prisma-airs-cli 2.12.0 → 3.0.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 (392) hide show
  1. package/README.md +27 -169
  2. package/dist/chunk-JXHYQFEK.js +1752 -0
  3. package/dist/cli/index.js +6511 -4
  4. package/dist/dlp-5XKWITZX.js +710 -0
  5. package/dist/index.d.ts +1396 -26
  6. package/dist/index.js +40 -37
  7. package/package.json +22 -25
  8. package/dist/airs/dlp/data-filtering-profiles.d.ts +0 -10
  9. package/dist/airs/dlp/data-filtering-profiles.d.ts.map +0 -1
  10. package/dist/airs/dlp/data-filtering-profiles.js +0 -17
  11. package/dist/airs/dlp/data-filtering-profiles.js.map +0 -1
  12. package/dist/airs/dlp/data-patterns.d.ts +0 -13
  13. package/dist/airs/dlp/data-patterns.d.ts.map +0 -1
  14. package/dist/airs/dlp/data-patterns.js +0 -26
  15. package/dist/airs/dlp/data-patterns.js.map +0 -1
  16. package/dist/airs/dlp/data-profiles.d.ts +0 -12
  17. package/dist/airs/dlp/data-profiles.d.ts.map +0 -1
  18. package/dist/airs/dlp/data-profiles.js +0 -23
  19. package/dist/airs/dlp/data-profiles.js.map +0 -1
  20. package/dist/airs/dlp/dictionaries.d.ts +0 -13
  21. package/dist/airs/dlp/dictionaries.d.ts.map +0 -1
  22. package/dist/airs/dlp/dictionaries.js +0 -34
  23. package/dist/airs/dlp/dictionaries.js.map +0 -1
  24. package/dist/airs/dlp/index.d.ts +0 -6
  25. package/dist/airs/dlp/index.d.ts.map +0 -1
  26. package/dist/airs/dlp/index.js +0 -6
  27. package/dist/airs/dlp/index.js.map +0 -1
  28. package/dist/airs/dlp/types.d.ts +0 -36
  29. package/dist/airs/dlp/types.d.ts.map +0 -1
  30. package/dist/airs/dlp/types.js +0 -2
  31. package/dist/airs/dlp/types.js.map +0 -1
  32. package/dist/airs/management.d.ts +0 -69
  33. package/dist/airs/management.d.ts.map +0 -1
  34. package/dist/airs/management.js +0 -370
  35. package/dist/airs/management.js.map +0 -1
  36. package/dist/airs/modelsecurity.d.ts +0 -74
  37. package/dist/airs/modelsecurity.d.ts.map +0 -1
  38. package/dist/airs/modelsecurity.js +0 -337
  39. package/dist/airs/modelsecurity.js.map +0 -1
  40. package/dist/airs/promptsets.d.ts +0 -50
  41. package/dist/airs/promptsets.d.ts.map +0 -1
  42. package/dist/airs/promptsets.js +0 -120
  43. package/dist/airs/promptsets.js.map +0 -1
  44. package/dist/airs/redteam.d.ts +0 -75
  45. package/dist/airs/redteam.d.ts.map +0 -1
  46. package/dist/airs/redteam.js +0 -418
  47. package/dist/airs/redteam.js.map +0 -1
  48. package/dist/airs/runtime.d.ts +0 -27
  49. package/dist/airs/runtime.d.ts.map +0 -1
  50. package/dist/airs/runtime.js +0 -158
  51. package/dist/airs/runtime.js.map +0 -1
  52. package/dist/airs/scanner.d.ts +0 -36
  53. package/dist/airs/scanner.d.ts.map +0 -1
  54. package/dist/airs/scanner.js +0 -101
  55. package/dist/airs/scanner.js.map +0 -1
  56. package/dist/airs/types.d.ts +0 -838
  57. package/dist/airs/types.d.ts.map +0 -1
  58. package/dist/airs/types.js +0 -6
  59. package/dist/airs/types.js.map +0 -1
  60. package/dist/audit/evaluator.d.ts +0 -17
  61. package/dist/audit/evaluator.d.ts.map +0 -1
  62. package/dist/audit/evaluator.js +0 -82
  63. package/dist/audit/evaluator.js.map +0 -1
  64. package/dist/audit/report.d.ts +0 -38
  65. package/dist/audit/report.d.ts.map +0 -1
  66. package/dist/audit/report.js +0 -141
  67. package/dist/audit/report.js.map +0 -1
  68. package/dist/audit/runner.d.ts +0 -18
  69. package/dist/audit/runner.d.ts.map +0 -1
  70. package/dist/audit/runner.js +0 -60
  71. package/dist/audit/runner.js.map +0 -1
  72. package/dist/audit/types.d.ts +0 -53
  73. package/dist/audit/types.d.ts.map +0 -1
  74. package/dist/audit/types.js +0 -5
  75. package/dist/audit/types.js.map +0 -1
  76. package/dist/backup/index.d.ts +0 -3
  77. package/dist/backup/index.d.ts.map +0 -1
  78. package/dist/backup/index.js +0 -3
  79. package/dist/backup/index.js.map +0 -1
  80. package/dist/backup/io.d.ts +0 -15
  81. package/dist/backup/io.d.ts.map +0 -1
  82. package/dist/backup/io.js +0 -67
  83. package/dist/backup/io.js.map +0 -1
  84. package/dist/backup/types.d.ts +0 -25
  85. package/dist/backup/types.d.ts.map +0 -1
  86. package/dist/backup/types.js +0 -2
  87. package/dist/backup/types.js.map +0 -1
  88. package/dist/cli/builders/profile-builder.d.ts +0 -45
  89. package/dist/cli/builders/profile-builder.d.ts.map +0 -1
  90. package/dist/cli/builders/profile-builder.js +0 -308
  91. package/dist/cli/builders/profile-builder.js.map +0 -1
  92. package/dist/cli/bulk-scan-state.d.ts +0 -15
  93. package/dist/cli/bulk-scan-state.d.ts.map +0 -1
  94. package/dist/cli/bulk-scan-state.js +0 -20
  95. package/dist/cli/bulk-scan-state.js.map +0 -1
  96. package/dist/cli/commands/audit.d.ts +0 -4
  97. package/dist/cli/commands/audit.d.ts.map +0 -1
  98. package/dist/cli/commands/audit.js +0 -113
  99. package/dist/cli/commands/audit.js.map +0 -1
  100. package/dist/cli/commands/backup.d.ts +0 -10
  101. package/dist/cli/commands/backup.d.ts.map +0 -1
  102. package/dist/cli/commands/backup.js +0 -102
  103. package/dist/cli/commands/backup.js.map +0 -1
  104. package/dist/cli/commands/dlp/build-body.d.ts +0 -28
  105. package/dist/cli/commands/dlp/build-body.d.ts.map +0 -1
  106. package/dist/cli/commands/dlp/build-body.js +0 -174
  107. package/dist/cli/commands/dlp/build-body.js.map +0 -1
  108. package/dist/cli/commands/dlp/dictionaries.d.ts +0 -3
  109. package/dist/cli/commands/dlp/dictionaries.d.ts.map +0 -1
  110. package/dist/cli/commands/dlp/dictionaries.js +0 -167
  111. package/dist/cli/commands/dlp/dictionaries.js.map +0 -1
  112. package/dist/cli/commands/dlp/filtering-profiles.d.ts +0 -3
  113. package/dist/cli/commands/dlp/filtering-profiles.d.ts.map +0 -1
  114. package/dist/cli/commands/dlp/filtering-profiles.js +0 -82
  115. package/dist/cli/commands/dlp/filtering-profiles.js.map +0 -1
  116. package/dist/cli/commands/dlp/generate.d.ts +0 -3
  117. package/dist/cli/commands/dlp/generate.d.ts.map +0 -1
  118. package/dist/cli/commands/dlp/generate.js +0 -51
  119. package/dist/cli/commands/dlp/generate.js.map +0 -1
  120. package/dist/cli/commands/dlp/index.d.ts +0 -3
  121. package/dist/cli/commands/dlp/index.d.ts.map +0 -1
  122. package/dist/cli/commands/dlp/index.js +0 -16
  123. package/dist/cli/commands/dlp/index.js.map +0 -1
  124. package/dist/cli/commands/dlp/patch.d.ts +0 -15
  125. package/dist/cli/commands/dlp/patch.d.ts.map +0 -1
  126. package/dist/cli/commands/dlp/patch.js +0 -70
  127. package/dist/cli/commands/dlp/patch.js.map +0 -1
  128. package/dist/cli/commands/dlp/patterns.d.ts +0 -3
  129. package/dist/cli/commands/dlp/patterns.d.ts.map +0 -1
  130. package/dist/cli/commands/dlp/patterns.js +0 -127
  131. package/dist/cli/commands/dlp/patterns.js.map +0 -1
  132. package/dist/cli/commands/dlp/profiles.d.ts +0 -3
  133. package/dist/cli/commands/dlp/profiles.d.ts.map +0 -1
  134. package/dist/cli/commands/dlp/profiles.js +0 -126
  135. package/dist/cli/commands/dlp/profiles.js.map +0 -1
  136. package/dist/cli/commands/modelsecurity.d.ts +0 -4
  137. package/dist/cli/commands/modelsecurity.d.ts.map +0 -1
  138. package/dist/cli/commands/modelsecurity.js +0 -605
  139. package/dist/cli/commands/modelsecurity.js.map +0 -1
  140. package/dist/cli/commands/profiles-cleanup.d.ts +0 -26
  141. package/dist/cli/commands/profiles-cleanup.d.ts.map +0 -1
  142. package/dist/cli/commands/profiles-cleanup.js +0 -113
  143. package/dist/cli/commands/profiles-cleanup.js.map +0 -1
  144. package/dist/cli/commands/redteam.d.ts +0 -12
  145. package/dist/cli/commands/redteam.d.ts.map +0 -1
  146. package/dist/cli/commands/redteam.js +0 -1075
  147. package/dist/cli/commands/redteam.js.map +0 -1
  148. package/dist/cli/commands/restore.d.ts +0 -11
  149. package/dist/cli/commands/restore.d.ts.map +0 -1
  150. package/dist/cli/commands/restore.js +0 -109
  151. package/dist/cli/commands/restore.js.map +0 -1
  152. package/dist/cli/commands/runtime.d.ts +0 -6
  153. package/dist/cli/commands/runtime.d.ts.map +0 -1
  154. package/dist/cli/commands/runtime.js +0 -869
  155. package/dist/cli/commands/runtime.js.map +0 -1
  156. package/dist/cli/commands/topics-apply.d.ts +0 -16
  157. package/dist/cli/commands/topics-apply.d.ts.map +0 -1
  158. package/dist/cli/commands/topics-apply.js +0 -69
  159. package/dist/cli/commands/topics-apply.js.map +0 -1
  160. package/dist/cli/commands/topics-create.d.ts +0 -16
  161. package/dist/cli/commands/topics-create.d.ts.map +0 -1
  162. package/dist/cli/commands/topics-create.js +0 -71
  163. package/dist/cli/commands/topics-create.js.map +0 -1
  164. package/dist/cli/commands/topics-eval.d.ts +0 -7
  165. package/dist/cli/commands/topics-eval.d.ts.map +0 -1
  166. package/dist/cli/commands/topics-eval.js +0 -65
  167. package/dist/cli/commands/topics-eval.js.map +0 -1
  168. package/dist/cli/commands/topics-revert.d.ts +0 -9
  169. package/dist/cli/commands/topics-revert.d.ts.map +0 -1
  170. package/dist/cli/commands/topics-revert.js +0 -52
  171. package/dist/cli/commands/topics-revert.js.map +0 -1
  172. package/dist/cli/commands/topics-sample.d.ts +0 -4
  173. package/dist/cli/commands/topics-sample.d.ts.map +0 -1
  174. package/dist/cli/commands/topics-sample.js +0 -27
  175. package/dist/cli/commands/topics-sample.js.map +0 -1
  176. package/dist/cli/debug-logger.d.ts +0 -11
  177. package/dist/cli/debug-logger.d.ts.map +0 -1
  178. package/dist/cli/debug-logger.js +0 -137
  179. package/dist/cli/debug-logger.js.map +0 -1
  180. package/dist/cli/index.d.ts +0 -3
  181. package/dist/cli/index.d.ts.map +0 -1
  182. package/dist/cli/index.js.map +0 -1
  183. package/dist/cli/parse-input.d.ts +0 -9
  184. package/dist/cli/parse-input.d.ts.map +0 -1
  185. package/dist/cli/parse-input.js +0 -109
  186. package/dist/cli/parse-input.js.map +0 -1
  187. package/dist/cli/program.d.ts +0 -3
  188. package/dist/cli/program.d.ts.map +0 -1
  189. package/dist/cli/program.js +0 -32
  190. package/dist/cli/program.js.map +0 -1
  191. package/dist/cli/renderer/audit.d.ts +0 -11
  192. package/dist/cli/renderer/audit.d.ts.map +0 -1
  193. package/dist/cli/renderer/audit.js +0 -58
  194. package/dist/cli/renderer/audit.js.map +0 -1
  195. package/dist/cli/renderer/backup.d.ts +0 -8
  196. package/dist/cli/renderer/backup.d.ts.map +0 -1
  197. package/dist/cli/renderer/backup.js +0 -50
  198. package/dist/cli/renderer/backup.js.map +0 -1
  199. package/dist/cli/renderer/common.d.ts +0 -14
  200. package/dist/cli/renderer/common.d.ts.map +0 -1
  201. package/dist/cli/renderer/common.js +0 -50
  202. package/dist/cli/renderer/common.js.map +0 -1
  203. package/dist/cli/renderer/dlp.d.ts +0 -34
  204. package/dist/cli/renderer/dlp.d.ts.map +0 -1
  205. package/dist/cli/renderer/dlp.js +0 -348
  206. package/dist/cli/renderer/dlp.js.map +0 -1
  207. package/dist/cli/renderer/eval.d.ts +0 -30
  208. package/dist/cli/renderer/eval.d.ts.map +0 -1
  209. package/dist/cli/renderer/eval.js +0 -61
  210. package/dist/cli/renderer/eval.js.map +0 -1
  211. package/dist/cli/renderer/index.d.ts +0 -9
  212. package/dist/cli/renderer/index.d.ts.map +0 -1
  213. package/dist/cli/renderer/index.js +0 -9
  214. package/dist/cli/renderer/index.js.map +0 -1
  215. package/dist/cli/renderer/modelsecurity.d.ts +0 -35
  216. package/dist/cli/renderer/modelsecurity.d.ts.map +0 -1
  217. package/dist/cli/renderer/modelsecurity.js +0 -339
  218. package/dist/cli/renderer/modelsecurity.js.map +0 -1
  219. package/dist/cli/renderer/redteam.d.ts +0 -224
  220. package/dist/cli/renderer/redteam.d.ts.map +0 -1
  221. package/dist/cli/renderer/redteam.js +0 -500
  222. package/dist/cli/renderer/redteam.js.map +0 -1
  223. package/dist/cli/renderer/runtime.d.ts +0 -135
  224. package/dist/cli/renderer/runtime.d.ts.map +0 -1
  225. package/dist/cli/renderer/runtime.js +0 -426
  226. package/dist/cli/renderer/runtime.js.map +0 -1
  227. package/dist/config/loader.d.ts +0 -3
  228. package/dist/config/loader.d.ts.map +0 -1
  229. package/dist/config/loader.js +0 -59
  230. package/dist/config/loader.js.map +0 -1
  231. package/dist/config/schema.d.ts +0 -63
  232. package/dist/config/schema.d.ts.map +0 -1
  233. package/dist/config/schema.js +0 -38
  234. package/dist/config/schema.js.map +0 -1
  235. package/dist/core/constraints.d.ts +0 -19
  236. package/dist/core/constraints.d.ts.map +0 -1
  237. package/dist/core/constraints.js +0 -82
  238. package/dist/core/constraints.js.map +0 -1
  239. package/dist/core/metrics.d.ts +0 -13
  240. package/dist/core/metrics.d.ts.map +0 -1
  241. package/dist/core/metrics.js +0 -73
  242. package/dist/core/metrics.js.map +0 -1
  243. package/dist/core/prompt-loader.d.ts +0 -14
  244. package/dist/core/prompt-loader.d.ts.map +0 -1
  245. package/dist/core/prompt-loader.js +0 -122
  246. package/dist/core/prompt-loader.js.map +0 -1
  247. package/dist/core/types.d.ts +0 -96
  248. package/dist/core/types.d.ts.map +0 -1
  249. package/dist/core/types.js +0 -5
  250. package/dist/core/types.js.map +0 -1
  251. package/dist/dlp/embed/docx.d.ts +0 -3
  252. package/dist/dlp/embed/docx.d.ts.map +0 -1
  253. package/dist/dlp/embed/docx.js +0 -63
  254. package/dist/dlp/embed/docx.js.map +0 -1
  255. package/dist/dlp/embed/index.d.ts +0 -6
  256. package/dist/dlp/embed/index.d.ts.map +0 -1
  257. package/dist/dlp/embed/index.js +0 -20
  258. package/dist/dlp/embed/index.js.map +0 -1
  259. package/dist/dlp/embed/jpeg.d.ts +0 -5
  260. package/dist/dlp/embed/jpeg.d.ts.map +0 -1
  261. package/dist/dlp/embed/jpeg.js +0 -67
  262. package/dist/dlp/embed/jpeg.js.map +0 -1
  263. package/dist/dlp/embed/overlay.d.ts +0 -7
  264. package/dist/dlp/embed/overlay.d.ts.map +0 -1
  265. package/dist/dlp/embed/overlay.js +0 -21
  266. package/dist/dlp/embed/overlay.js.map +0 -1
  267. package/dist/dlp/embed/pdf.d.ts +0 -7
  268. package/dist/dlp/embed/pdf.d.ts.map +0 -1
  269. package/dist/dlp/embed/pdf.js +0 -124
  270. package/dist/dlp/embed/pdf.js.map +0 -1
  271. package/dist/dlp/embed/png-chunks.d.ts +0 -12
  272. package/dist/dlp/embed/png-chunks.d.ts.map +0 -1
  273. package/dist/dlp/embed/png-chunks.js +0 -85
  274. package/dist/dlp/embed/png-chunks.js.map +0 -1
  275. package/dist/dlp/embed/png.d.ts +0 -5
  276. package/dist/dlp/embed/png.d.ts.map +0 -1
  277. package/dist/dlp/embed/png.js +0 -75
  278. package/dist/dlp/embed/png.js.map +0 -1
  279. package/dist/dlp/embed/svg.d.ts +0 -3
  280. package/dist/dlp/embed/svg.d.ts.map +0 -1
  281. package/dist/dlp/embed/svg.js +0 -43
  282. package/dist/dlp/embed/svg.js.map +0 -1
  283. package/dist/dlp/embed/zip.d.ts +0 -3
  284. package/dist/dlp/embed/zip.d.ts.map +0 -1
  285. package/dist/dlp/embed/zip.js +0 -25
  286. package/dist/dlp/embed/zip.js.map +0 -1
  287. package/dist/dlp/generate/docx.d.ts +0 -3
  288. package/dist/dlp/generate/docx.d.ts.map +0 -1
  289. package/dist/dlp/generate/docx.js +0 -24
  290. package/dist/dlp/generate/docx.js.map +0 -1
  291. package/dist/dlp/generate/index.d.ts +0 -5
  292. package/dist/dlp/generate/index.d.ts.map +0 -1
  293. package/dist/dlp/generate/index.js +0 -21
  294. package/dist/dlp/generate/index.js.map +0 -1
  295. package/dist/dlp/generate/jpeg.d.ts +0 -3
  296. package/dist/dlp/generate/jpeg.d.ts.map +0 -1
  297. package/dist/dlp/generate/jpeg.js +0 -8
  298. package/dist/dlp/generate/jpeg.js.map +0 -1
  299. package/dist/dlp/generate/pdf.d.ts +0 -3
  300. package/dist/dlp/generate/pdf.d.ts.map +0 -1
  301. package/dist/dlp/generate/pdf.js +0 -19
  302. package/dist/dlp/generate/pdf.js.map +0 -1
  303. package/dist/dlp/generate/png.d.ts +0 -3
  304. package/dist/dlp/generate/png.d.ts.map +0 -1
  305. package/dist/dlp/generate/png.js +0 -8
  306. package/dist/dlp/generate/png.js.map +0 -1
  307. package/dist/dlp/generate/raster.d.ts +0 -9
  308. package/dist/dlp/generate/raster.d.ts.map +0 -1
  309. package/dist/dlp/generate/raster.js +0 -20
  310. package/dist/dlp/generate/raster.js.map +0 -1
  311. package/dist/dlp/generate/svg.d.ts +0 -3
  312. package/dist/dlp/generate/svg.d.ts.map +0 -1
  313. package/dist/dlp/generate/svg.js +0 -17
  314. package/dist/dlp/generate/svg.js.map +0 -1
  315. package/dist/dlp/index.d.ts +0 -15
  316. package/dist/dlp/index.d.ts.map +0 -1
  317. package/dist/dlp/index.js +0 -54
  318. package/dist/dlp/index.js.map +0 -1
  319. package/dist/dlp/lorem.d.ts +0 -3
  320. package/dist/dlp/lorem.d.ts.map +0 -1
  321. package/dist/dlp/lorem.js +0 -65
  322. package/dist/dlp/lorem.js.map +0 -1
  323. package/dist/dlp/manifest.d.ts +0 -11
  324. package/dist/dlp/manifest.d.ts.map +0 -1
  325. package/dist/dlp/manifest.js +0 -14
  326. package/dist/dlp/manifest.js.map +0 -1
  327. package/dist/dlp/payload.d.ts +0 -6
  328. package/dist/dlp/payload.d.ts.map +0 -1
  329. package/dist/dlp/payload.js +0 -62
  330. package/dist/dlp/payload.js.map +0 -1
  331. package/dist/dlp/rng.d.ts +0 -9
  332. package/dist/dlp/rng.d.ts.map +0 -1
  333. package/dist/dlp/rng.js +0 -28
  334. package/dist/dlp/rng.js.map +0 -1
  335. package/dist/dlp/types.d.ts +0 -26
  336. package/dist/dlp/types.d.ts.map +0 -1
  337. package/dist/dlp/types.js +0 -2
  338. package/dist/dlp/types.js.map +0 -1
  339. package/dist/index.d.ts.map +0 -1
  340. package/dist/index.js.map +0 -1
  341. package/dist/llm/prompts/analyze-results.d.ts +0 -3
  342. package/dist/llm/prompts/analyze-results.d.ts.map +0 -1
  343. package/dist/llm/prompts/analyze-results.js +0 -52
  344. package/dist/llm/prompts/analyze-results.js.map +0 -1
  345. package/dist/llm/prompts/generate-companion.d.ts +0 -3
  346. package/dist/llm/prompts/generate-companion.d.ts.map +0 -1
  347. package/dist/llm/prompts/generate-companion.js +0 -42
  348. package/dist/llm/prompts/generate-companion.js.map +0 -1
  349. package/dist/llm/prompts/generate-tests.d.ts +0 -3
  350. package/dist/llm/prompts/generate-tests.d.ts.map +0 -1
  351. package/dist/llm/prompts/generate-tests.js +0 -46
  352. package/dist/llm/prompts/generate-tests.js.map +0 -1
  353. package/dist/llm/prompts/generate-topic.d.ts +0 -4
  354. package/dist/llm/prompts/generate-topic.d.ts.map +0 -1
  355. package/dist/llm/prompts/generate-topic.js +0 -41
  356. package/dist/llm/prompts/generate-topic.js.map +0 -1
  357. package/dist/llm/prompts/improve-topic.d.ts +0 -3
  358. package/dist/llm/prompts/improve-topic.d.ts.map +0 -1
  359. package/dist/llm/prompts/improve-topic.js +0 -77
  360. package/dist/llm/prompts/improve-topic.js.map +0 -1
  361. package/dist/llm/prompts/simplify-topic.d.ts +0 -3
  362. package/dist/llm/prompts/simplify-topic.d.ts.map +0 -1
  363. package/dist/llm/prompts/simplify-topic.js +0 -50
  364. package/dist/llm/prompts/simplify-topic.js.map +0 -1
  365. package/dist/llm/provider.d.ts +0 -21
  366. package/dist/llm/provider.d.ts.map +0 -1
  367. package/dist/llm/provider.js +0 -76
  368. package/dist/llm/provider.js.map +0 -1
  369. package/dist/llm/schemas.d.ts +0 -97
  370. package/dist/llm/schemas.d.ts.map +0 -1
  371. package/dist/llm/schemas.js +0 -24
  372. package/dist/llm/schemas.js.map +0 -1
  373. package/dist/llm/service.d.ts +0 -34
  374. package/dist/llm/service.d.ts.map +0 -1
  375. package/dist/llm/service.js +0 -268
  376. package/dist/llm/service.js.map +0 -1
  377. package/dist/llm/types.d.ts +0 -18
  378. package/dist/llm/types.d.ts.map +0 -1
  379. package/dist/llm/types.js +0 -2
  380. package/dist/llm/types.js.map +0 -1
  381. package/dist/report/html.d.ts +0 -6
  382. package/dist/report/html.d.ts.map +0 -1
  383. package/dist/report/html.js +0 -200
  384. package/dist/report/html.js.map +0 -1
  385. package/dist/report/json.d.ts +0 -11
  386. package/dist/report/json.d.ts.map +0 -1
  387. package/dist/report/json.js +0 -74
  388. package/dist/report/json.js.map +0 -1
  389. package/dist/report/types.d.ts +0 -58
  390. package/dist/report/types.d.ts.map +0 -1
  391. package/dist/report/types.js +0 -5
  392. package/dist/report/types.js.map +0 -1
@@ -0,0 +1,1752 @@
1
+ // src/airs/management.ts
2
+ import {
3
+ ManagementClient
4
+ } from "@cdot65/prisma-airs-sdk";
5
+ var SdkManagementService = class {
6
+ client;
7
+ constructor(opts) {
8
+ this.client = getOrCreateManagementClient(opts);
9
+ }
10
+ async createTopic(request) {
11
+ return this.client.topics.create(request);
12
+ }
13
+ async updateTopic(topicId, request) {
14
+ return this.client.topics.update(topicId, request);
15
+ }
16
+ async deleteTopic(topicId) {
17
+ await this.client.topics.delete(topicId);
18
+ }
19
+ async forceDeleteTopic(topicId, updatedBy) {
20
+ const response = await this.client.topics.forceDelete(topicId, updatedBy);
21
+ return { message: response.message };
22
+ }
23
+ async listTopics() {
24
+ const response = await this.client.topics.list();
25
+ return response.custom_topics;
26
+ }
27
+ async getTopic(topicId) {
28
+ const topics = await this.listTopics();
29
+ const topic = topics.find((t) => t.topic_id === topicId);
30
+ if (!topic) throw new Error(`Topic ${topicId} not found`);
31
+ return topic;
32
+ }
33
+ async getTopicByName(topicName) {
34
+ const topics = await this.listTopics();
35
+ const topic = topics.find((t) => t.topic_name === topicName);
36
+ if (!topic) throw new Error(`Topic "${topicName}" not found`);
37
+ return topic;
38
+ }
39
+ /**
40
+ * Sets a single custom topic on a profile's topic-guardrails config.
41
+ * Delegates to {@link assignTopicsToProfile} for backward compatibility.
42
+ */
43
+ async assignTopicToProfile(profileName, topicId, topicName, action) {
44
+ return this.assignTopicsToProfile(profileName, [{ topicId, topicName, action }]);
45
+ }
46
+ /**
47
+ * Sets one or more custom topics on a profile's topic-guardrails config.
48
+ * Replaces any existing topics — previous runs' stale topics are cleared.
49
+ * Groups topics by action; skips empty action groups (AIRS rejects them).
50
+ *
51
+ * CRITICAL: Each topic entry MUST include the current `revision` number.
52
+ * AIRS pins topic content to the revision specified in the profile — omitting
53
+ * it defaults to revision 0 (original content), not the latest.
54
+ */
55
+ async assignTopicsToProfile(profileName, topics, guardrailAction) {
56
+ const { ai_profiles } = await this.client.profiles.list();
57
+ const profile = ai_profiles.find((p) => p.profile_name === profileName);
58
+ if (!profile?.profile_id) {
59
+ throw new Error(`Profile "${profileName}" not found`);
60
+ }
61
+ const allTopics = await this.listTopics();
62
+ const revisionMap = new Map(allTopics.map((t) => [t.topic_id, t.revision ?? 0]));
63
+ const policy = JSON.parse(JSON.stringify(profile.policy ?? {}));
64
+ const aiProfiles = policy["ai-security-profiles"] ?? [
65
+ { "model-type": "default", "model-configuration": {} }
66
+ ];
67
+ const modelConfig = aiProfiles[0]?.["model-configuration"] ?? {};
68
+ const modelProtection = modelConfig["model-protection"] ?? [];
69
+ let topicGuardrails = modelProtection.find((mp) => mp.name === "topic-guardrails");
70
+ if (!topicGuardrails) {
71
+ topicGuardrails = {
72
+ action: "block",
73
+ name: "topic-guardrails",
74
+ options: [],
75
+ "topic-list": []
76
+ };
77
+ modelProtection.push(topicGuardrails);
78
+ }
79
+ topicGuardrails.action = guardrailAction ?? "block";
80
+ const byAction = /* @__PURE__ */ new Map();
81
+ for (const t of topics) {
82
+ const group = byAction.get(t.action) ?? [];
83
+ group.push({
84
+ topic_id: t.topicId,
85
+ topic_name: t.topicName,
86
+ revision: revisionMap.get(t.topicId) ?? 0
87
+ });
88
+ byAction.set(t.action, group);
89
+ }
90
+ const topicList = [];
91
+ for (const [action, group] of byAction) {
92
+ topicList.push({ action, topic: group });
93
+ }
94
+ topicGuardrails["topic-list"] = topicList;
95
+ modelConfig["model-protection"] = modelProtection;
96
+ aiProfiles[0]["model-configuration"] = modelConfig;
97
+ policy["ai-security-profiles"] = aiProfiles;
98
+ await this.client.profiles.update(profile.profile_id, {
99
+ profile_name: profile.profile_name,
100
+ active: profile.active,
101
+ policy
102
+ });
103
+ }
104
+ async getProfileTopics(profileName) {
105
+ const { ai_profiles } = await this.client.profiles.list();
106
+ const profile = ai_profiles.find((p) => p.profile_name === profileName);
107
+ if (!profile?.profile_id) {
108
+ throw new Error(`Profile "${profileName}" not found`);
109
+ }
110
+ const policy = profile.policy ?? {};
111
+ const aiProfiles = policy["ai-security-profiles"] ?? [];
112
+ const modelConfig = aiProfiles[0]?.["model-configuration"] ?? {};
113
+ const modelProtection = modelConfig["model-protection"] ?? [];
114
+ const topicGuardrails = modelProtection.find((mp) => mp.name === "topic-guardrails");
115
+ if (!topicGuardrails) return [];
116
+ const topicList = topicGuardrails["topic-list"] ?? [];
117
+ const topicRefs = [];
118
+ for (const entry of topicList) {
119
+ for (const t of entry.topic ?? []) {
120
+ topicRefs.push({
121
+ topicId: t.topic_id,
122
+ topicName: t.topic_name,
123
+ action: entry.action
124
+ });
125
+ }
126
+ }
127
+ if (topicRefs.length === 0) return [];
128
+ const allTopics = await this.listTopics();
129
+ const topicMap = new Map(allTopics.map((t) => [t.topic_id, t]));
130
+ return topicRefs.map((ref) => {
131
+ const full = topicMap.get(ref.topicId);
132
+ return {
133
+ topicId: ref.topicId,
134
+ topicName: ref.topicName,
135
+ action: ref.action,
136
+ description: full?.description ?? "",
137
+ examples: full?.examples ?? []
138
+ };
139
+ });
140
+ }
141
+ // -------------------------------------------------------------------------
142
+ // Profile CRUD
143
+ // -------------------------------------------------------------------------
144
+ normalizeProfile(p) {
145
+ return {
146
+ profileId: p.profile_id,
147
+ profileName: p.profile_name,
148
+ revision: p.revision,
149
+ active: p.active,
150
+ createdBy: p.created_by,
151
+ updatedBy: p.updated_by,
152
+ lastModifiedTs: p.last_modified_ts,
153
+ policy: p.policy
154
+ };
155
+ }
156
+ async getProfile(profileId) {
157
+ const response = await this.client.profiles.get(profileId);
158
+ return this.normalizeProfile(response);
159
+ }
160
+ async getProfileByName(profileName) {
161
+ const response = await this.client.profiles.getByName(profileName);
162
+ return this.normalizeProfile(response);
163
+ }
164
+ async listProfiles(opts) {
165
+ const response = await this.client.profiles.list(opts);
166
+ return {
167
+ profiles: (response.ai_profiles ?? []).map(
168
+ (p) => this.normalizeProfile(p)
169
+ ),
170
+ nextOffset: response.next_offset
171
+ };
172
+ }
173
+ async createProfile(request) {
174
+ const response = await this.client.profiles.create(request);
175
+ return this.normalizeProfile(response);
176
+ }
177
+ async updateProfile(profileId, request) {
178
+ const response = await this.client.profiles.update(profileId, request);
179
+ return this.normalizeProfile(response);
180
+ }
181
+ async deleteProfile(profileId) {
182
+ const response = await this.client.profiles.delete(profileId);
183
+ return { message: response.message };
184
+ }
185
+ async forceDeleteProfile(profileId, updatedBy) {
186
+ const response = await this.client.profiles.forceDelete(profileId, updatedBy);
187
+ return { message: response.message };
188
+ }
189
+ // -------------------------------------------------------------------------
190
+ // API Keys
191
+ // -------------------------------------------------------------------------
192
+ normalizeApiKey(k) {
193
+ return {
194
+ id: k.id ?? k.api_key_id ?? "",
195
+ name: k.name ?? k.api_key_name ?? "",
196
+ apiKey: k.api_key,
197
+ last8: k.api_key_last8,
198
+ createdAt: k.created_at,
199
+ expiresAt: k.expires_at
200
+ };
201
+ }
202
+ async listApiKeys(opts) {
203
+ const response = await this.client.apiKeys.list(opts);
204
+ const raw = response;
205
+ const keys = raw.api_keys ?? [];
206
+ return {
207
+ apiKeys: keys.map((k) => this.normalizeApiKey(k)),
208
+ nextOffset: raw.next_offset
209
+ };
210
+ }
211
+ async createApiKey(request) {
212
+ const response = await this.client.apiKeys.create(request);
213
+ return this.normalizeApiKey(response);
214
+ }
215
+ async regenerateApiKey(apiKeyId, request) {
216
+ const response = await this.client.apiKeys.regenerate(apiKeyId, request);
217
+ return this.normalizeApiKey(response);
218
+ }
219
+ async deleteApiKey(apiKeyName, updatedBy) {
220
+ const response = await this.client.apiKeys.delete(apiKeyName, updatedBy);
221
+ return { message: response.message };
222
+ }
223
+ // -------------------------------------------------------------------------
224
+ // Customer Apps
225
+ // -------------------------------------------------------------------------
226
+ normalizeCustomerApp(a) {
227
+ return {
228
+ id: a.customer_app_id ?? a.id,
229
+ name: a.app_name ?? a.name ?? "",
230
+ description: a.description,
231
+ raw: a
232
+ };
233
+ }
234
+ async listCustomerApps(opts) {
235
+ const response = await this.client.customerApps.list(opts);
236
+ const raw = response;
237
+ const apps = raw.customer_apps ?? [];
238
+ return {
239
+ apps: apps.map((a) => this.normalizeCustomerApp(a)),
240
+ nextOffset: raw.next_offset
241
+ };
242
+ }
243
+ async getCustomerApp(appName) {
244
+ const response = await this.client.customerApps.get(appName);
245
+ return this.normalizeCustomerApp(response);
246
+ }
247
+ async updateCustomerApp(appId, request) {
248
+ const response = await this.client.customerApps.update(appId, request);
249
+ return this.normalizeCustomerApp(response);
250
+ }
251
+ async deleteCustomerApp(appName, updatedBy) {
252
+ const response = await this.client.customerApps.delete(appName, updatedBy);
253
+ return this.normalizeCustomerApp(response);
254
+ }
255
+ async listConsumptionApps(opts) {
256
+ const response = await this.client.dashboard.applicationsOverview({
257
+ limit: opts?.limit ?? 100,
258
+ offset: opts?.offset ?? 0
259
+ });
260
+ return (response.items ?? []).filter(
261
+ (item) => typeof item.id === "string" && typeof item.name === "string"
262
+ ).map((item) => ({
263
+ appId: item.id,
264
+ appName: item.name,
265
+ cloud: item.cloud ?? void 0,
266
+ source: item.source ?? void 0
267
+ }));
268
+ }
269
+ async getCustomerAppConsumption(appName, opts) {
270
+ const dashboardApps = await this.listConsumptionApps({ limit: 100 });
271
+ const target = dashboardApps.find((a) => a.appName === appName);
272
+ const appId = target?.appId;
273
+ if (!appId) {
274
+ const sample = dashboardApps.slice(0, 5).map((a) => `"${a.appName}"`).join(", ");
275
+ const more = dashboardApps.length > 5 ? `, ... (${dashboardApps.length} total)` : "";
276
+ throw new Error(
277
+ `Dashboard application not found: "${appName}". Available (as shown in SCM AI Applications view): ${sample}${more}. Note: the name to use is the literal value your integration sends in scan metadata.app_name (which may differ from the SCM application name).`
278
+ );
279
+ }
280
+ const timeInterval = opts?.timeInterval ?? 30;
281
+ const query = { appId, appName, timeInterval };
282
+ const [overview, breakdown] = await Promise.all([
283
+ this.client.dashboard.application(query),
284
+ this.client.dashboard.applicationViolationBreakdown(query)
285
+ ]);
286
+ const ts = overview.token_stats ?? {};
287
+ const ss = overview.session_stats ?? {};
288
+ const detectors = (breakdown.detection_type_violation_breakdown ?? []).map((entry) => {
289
+ const vb = entry.violation_breakdown ?? {};
290
+ return {
291
+ type: entry.detection_type ?? "unknown",
292
+ critical: vb.critical ?? 0,
293
+ high: vb.high ?? 0,
294
+ medium: vb.medium ?? 0,
295
+ low: vb.low ?? 0,
296
+ total: vb.total ?? 0
297
+ };
298
+ });
299
+ return {
300
+ appId,
301
+ appName,
302
+ cloud: overview.cloud ?? void 0,
303
+ source: overview.source ?? void 0,
304
+ monitoringSince: overview.created_at ?? void 0,
305
+ profiles: overview.profiles ?? [],
306
+ tokens: {
307
+ dailyAverage: ts.average_daily_tokens ?? void 0,
308
+ dailyAverageScale: ts.average_daily_tokens_scale ?? void 0,
309
+ monthlyTotal: ts.monthly_total_tokens ?? void 0,
310
+ monthlyTotalScale: ts.monthly_total_tokens_scale ?? void 0
311
+ },
312
+ sessions: {
313
+ total: ss.total ?? 0,
314
+ violating: ss.violating ?? 0
315
+ },
316
+ detectors,
317
+ totalViolating: breakdown.total_violating ?? 0
318
+ };
319
+ }
320
+ // -------------------------------------------------------------------------
321
+ // Deployment Profiles (read-only)
322
+ // -------------------------------------------------------------------------
323
+ async listDeploymentProfiles(opts) {
324
+ const response = await this.client.deploymentProfiles.list(opts);
325
+ const raw = response;
326
+ const profiles = raw.deployment_profiles ?? [];
327
+ return profiles.map((p) => ({ raw: p }));
328
+ }
329
+ // -------------------------------------------------------------------------
330
+ // Scan Logs
331
+ // -------------------------------------------------------------------------
332
+ async queryScanLogs(opts) {
333
+ const response = await this.client.scanLogs.query({
334
+ time_interval: opts.timeInterval,
335
+ time_unit: opts.timeUnit,
336
+ pageNumber: opts.pageNumber,
337
+ pageSize: opts.pageSize,
338
+ filter: opts.filter,
339
+ page_token: opts.pageToken
340
+ });
341
+ const raw = response;
342
+ const dashboard = raw.scan_result_for_dashboard ?? {};
343
+ const entries = dashboard.scan_result_entries ?? raw.results ?? [];
344
+ return {
345
+ results: entries,
346
+ pageToken: raw.page_token,
347
+ raw
348
+ };
349
+ }
350
+ };
351
+ var _sharedClient;
352
+ function getOrCreateManagementClient(opts) {
353
+ if (!_sharedClient) {
354
+ _sharedClient = new ManagementClient(opts);
355
+ }
356
+ return _sharedClient;
357
+ }
358
+
359
+ // src/airs/modelsecurity.ts
360
+ import { ModelSecurityClient } from "@cdot65/prisma-airs-sdk";
361
+ function normalizeGroup(raw) {
362
+ return {
363
+ uuid: raw.uuid,
364
+ name: raw.name,
365
+ description: raw.description,
366
+ sourceType: raw.source_type,
367
+ state: raw.state,
368
+ createdAt: raw.created_at,
369
+ updatedAt: raw.updated_at
370
+ };
371
+ }
372
+ function normalizeRuleInstance(raw) {
373
+ return {
374
+ uuid: raw.uuid,
375
+ securityGroupUuid: raw.security_group_uuid,
376
+ securityRuleUuid: raw.security_rule_uuid,
377
+ state: raw.state,
378
+ createdAt: raw.created_at,
379
+ updatedAt: raw.updated_at,
380
+ rule: raw.rule,
381
+ fieldValues: raw.field_values ?? {}
382
+ };
383
+ }
384
+ function normalizeRule(raw) {
385
+ const editableFields = raw.editable_fields ?? [];
386
+ return {
387
+ uuid: raw.uuid,
388
+ name: raw.name,
389
+ description: raw.description,
390
+ ruleType: raw.rule_type,
391
+ compatibleSources: raw.compatible_sources,
392
+ defaultState: raw.default_state,
393
+ remediation: raw.remediation,
394
+ editableFields: editableFields.map(
395
+ (f) => ({
396
+ attributeName: f.attribute_name,
397
+ type: f.type,
398
+ displayName: f.display_name,
399
+ displayType: f.display_type,
400
+ description: f.description,
401
+ dropdownValues: f.dropdown_values
402
+ })
403
+ ),
404
+ constantValues: raw.constant_values ?? {},
405
+ defaultValues: raw.default_values ?? {}
406
+ };
407
+ }
408
+ function normalizeScan(raw) {
409
+ const summary = raw.eval_summary;
410
+ return {
411
+ uuid: raw.uuid,
412
+ evalOutcome: raw.eval_outcome ?? "",
413
+ modelUri: raw.model_uri ?? "",
414
+ scanOrigin: raw.scan_origin ?? "",
415
+ sourceType: raw.source_type ?? "",
416
+ securityGroupName: raw.security_group_name ?? "",
417
+ evalSummary: summary ? {
418
+ rulesFailed: summary.rules_failed ?? 0,
419
+ rulesPassed: summary.rules_passed ?? 0,
420
+ totalRules: summary.total_rules ?? 0
421
+ } : null,
422
+ createdAt: raw.created_at,
423
+ updatedAt: raw.updated_at,
424
+ labels: raw.labels ?? []
425
+ };
426
+ }
427
+ function normalizeEvaluation(raw) {
428
+ return {
429
+ uuid: raw.uuid,
430
+ result: raw.result,
431
+ violationCount: raw.violation_count ?? 0,
432
+ ruleInstanceUuid: raw.rule_instance_uuid ?? "",
433
+ ruleName: raw.rule_name,
434
+ ruleDescription: raw.rule_description ?? "",
435
+ ruleInstanceState: raw.rule_instance_state ?? ""
436
+ };
437
+ }
438
+ function normalizeViolation(raw) {
439
+ return {
440
+ uuid: raw.uuid,
441
+ description: raw.description,
442
+ threat: raw.threat ?? "",
443
+ threatDescription: raw.threat_description ?? "",
444
+ file: raw.file ?? "",
445
+ ruleName: raw.rule_name,
446
+ ruleDescription: raw.rule_description ?? "",
447
+ ruleInstanceState: raw.rule_instance_state ?? ""
448
+ };
449
+ }
450
+ function normalizeFile(raw) {
451
+ return {
452
+ uuid: raw.uuid,
453
+ path: raw.path ?? "",
454
+ type: raw.type,
455
+ formats: raw.formats ?? [],
456
+ result: raw.result
457
+ };
458
+ }
459
+ var SdkModelSecurityService = class {
460
+ client;
461
+ constructor(opts) {
462
+ this.client = new ModelSecurityClient(opts);
463
+ }
464
+ // -----------------------------------------------------------------------
465
+ // Security Groups
466
+ // -----------------------------------------------------------------------
467
+ async listGroups(opts) {
468
+ const sdkOpts = {};
469
+ if (opts?.sourceTypes) sdkOpts.source_types = opts.sourceTypes;
470
+ if (opts?.searchQuery) sdkOpts.search_query = opts.searchQuery;
471
+ if (opts?.sortField) sdkOpts.sort_field = opts.sortField;
472
+ if (opts?.sortDir) sdkOpts.sort_dir = opts.sortDir;
473
+ if (opts?.enabledRules) sdkOpts.enabled_rules = opts.enabledRules;
474
+ if (opts?.skip !== void 0) sdkOpts.skip = opts.skip;
475
+ if (opts?.limit !== void 0) sdkOpts.limit = opts.limit;
476
+ const response = await this.client.securityGroups.list(sdkOpts);
477
+ const raw = response;
478
+ return {
479
+ totalItems: raw.pagination.total_items ?? 0,
480
+ groups: raw.security_groups.map(normalizeGroup)
481
+ };
482
+ }
483
+ async getGroup(uuid) {
484
+ const response = await this.client.securityGroups.get(uuid);
485
+ return normalizeGroup(response);
486
+ }
487
+ async createGroup(request) {
488
+ const sdkRequest = {
489
+ name: request.name,
490
+ source_type: request.sourceType
491
+ };
492
+ if (request.description !== void 0) sdkRequest.description = request.description;
493
+ if (request.ruleConfigurations) sdkRequest.rule_configurations = request.ruleConfigurations;
494
+ const response = await this.client.securityGroups.create(sdkRequest);
495
+ return normalizeGroup(response);
496
+ }
497
+ async updateGroup(uuid, request) {
498
+ const response = await this.client.securityGroups.update(uuid, request);
499
+ return normalizeGroup(response);
500
+ }
501
+ async deleteGroup(uuid) {
502
+ await this.client.securityGroups.delete(uuid);
503
+ }
504
+ /**
505
+ * Delete a group, then verify whether it is actually gone. The API soft/async-deletes
506
+ * security groups — a successful DELETE does not immediately remove the resource, so a
507
+ * follow-up `get` may still return it as ACTIVE (see prisma-airs-cli#239). The SDK delete
508
+ * returns void, so re-reading is the only way to report the real outcome rather than
509
+ * claiming an unconditional success. Returns `{ confirmed: true }` when the group no longer
510
+ * resolves, or `{ confirmed: false, state }` when it still does.
511
+ */
512
+ async deleteGroupAndVerify(uuid) {
513
+ await this.deleteGroup(uuid);
514
+ try {
515
+ const group = await this.getGroup(uuid);
516
+ return { confirmed: false, state: group.state };
517
+ } catch {
518
+ return { confirmed: true };
519
+ }
520
+ }
521
+ // -----------------------------------------------------------------------
522
+ // Rule Instances
523
+ // -----------------------------------------------------------------------
524
+ async listRuleInstances(groupUuid, opts) {
525
+ const sdkOpts = {};
526
+ if (opts?.securityRuleUuid) sdkOpts.security_rule_uuid = opts.securityRuleUuid;
527
+ if (opts?.state) sdkOpts.state = opts.state;
528
+ if (opts?.skip !== void 0) sdkOpts.skip = opts.skip;
529
+ if (opts?.limit !== void 0) sdkOpts.limit = opts.limit;
530
+ const response = await this.client.securityGroups.listRuleInstances(
531
+ groupUuid,
532
+ sdkOpts
533
+ );
534
+ const raw = response;
535
+ return {
536
+ totalItems: raw.pagination.total_items ?? 0,
537
+ ruleInstances: raw.rule_instances.map(normalizeRuleInstance)
538
+ };
539
+ }
540
+ async getRuleInstance(groupUuid, instanceUuid) {
541
+ const response = await this.client.securityGroups.getRuleInstance(groupUuid, instanceUuid);
542
+ return normalizeRuleInstance(response);
543
+ }
544
+ async updateRuleInstance(groupUuid, instanceUuid, request) {
545
+ const sdkRequest = {
546
+ security_group_uuid: groupUuid
547
+ };
548
+ if (request.state !== void 0) sdkRequest.state = request.state;
549
+ if (request.fieldValues !== void 0) sdkRequest.field_values = request.fieldValues;
550
+ const response = await this.client.securityGroups.updateRuleInstance(
551
+ groupUuid,
552
+ instanceUuid,
553
+ sdkRequest
554
+ );
555
+ return normalizeRuleInstance(response);
556
+ }
557
+ // -----------------------------------------------------------------------
558
+ // Security Rules
559
+ // -----------------------------------------------------------------------
560
+ async listRules(opts) {
561
+ const sdkOpts = {};
562
+ if (opts?.sourceType) sdkOpts.source_type = opts.sourceType;
563
+ if (opts?.searchQuery) sdkOpts.search_query = opts.searchQuery;
564
+ if (opts?.skip !== void 0) sdkOpts.skip = opts.skip;
565
+ if (opts?.limit !== void 0) sdkOpts.limit = opts.limit;
566
+ const response = await this.client.securityRules.list(sdkOpts);
567
+ const raw = response;
568
+ return {
569
+ totalItems: raw.pagination.total_items ?? 0,
570
+ rules: raw.rules.map(normalizeRule)
571
+ };
572
+ }
573
+ async getRule(uuid) {
574
+ const response = await this.client.securityRules.get(uuid);
575
+ return normalizeRule(response);
576
+ }
577
+ // -----------------------------------------------------------------------
578
+ // Scans
579
+ // -----------------------------------------------------------------------
580
+ async createScan(request) {
581
+ const response = await this.client.scans.create(request);
582
+ return normalizeScan(response);
583
+ }
584
+ async listScans(opts) {
585
+ const sdkOpts = {};
586
+ if (opts?.evalOutcome) sdkOpts.eval_outcome = opts.evalOutcome;
587
+ if (opts?.sourceType) sdkOpts.source_type = opts.sourceType;
588
+ if (opts?.scanOrigin) sdkOpts.scan_origin = opts.scanOrigin;
589
+ if (opts?.search) sdkOpts.search = opts.search;
590
+ if (opts?.skip !== void 0) sdkOpts.skip = opts.skip;
591
+ if (opts?.limit !== void 0) sdkOpts.limit = opts.limit;
592
+ const response = await this.client.scans.list(sdkOpts);
593
+ const raw = response;
594
+ return {
595
+ totalItems: raw.pagination.total_items ?? 0,
596
+ scans: raw.scans.map(normalizeScan)
597
+ };
598
+ }
599
+ async getScan(uuid) {
600
+ const response = await this.client.scans.get(uuid);
601
+ return normalizeScan(response);
602
+ }
603
+ // -----------------------------------------------------------------------
604
+ // Evaluations
605
+ // -----------------------------------------------------------------------
606
+ async getEvaluations(scanUuid, opts) {
607
+ const response = await this.client.scans.getEvaluations(scanUuid, opts);
608
+ const raw = response;
609
+ return {
610
+ totalItems: raw.pagination.total_items ?? 0,
611
+ evaluations: raw.evaluations.map(normalizeEvaluation)
612
+ };
613
+ }
614
+ async getEvaluation(uuid) {
615
+ const response = await this.client.scans.getEvaluation(uuid);
616
+ return normalizeEvaluation(response);
617
+ }
618
+ // -----------------------------------------------------------------------
619
+ // Violations
620
+ // -----------------------------------------------------------------------
621
+ async getViolations(scanUuid, opts) {
622
+ const response = await this.client.scans.getViolations(scanUuid, opts);
623
+ const raw = response;
624
+ return {
625
+ totalItems: raw.pagination.total_items ?? 0,
626
+ violations: raw.violations.map(normalizeViolation)
627
+ };
628
+ }
629
+ async getViolation(uuid) {
630
+ const response = await this.client.scans.getViolation(uuid);
631
+ return normalizeViolation(response);
632
+ }
633
+ // -----------------------------------------------------------------------
634
+ // Files
635
+ // -----------------------------------------------------------------------
636
+ async getFiles(scanUuid, opts) {
637
+ const response = await this.client.scans.getFiles(scanUuid, opts);
638
+ const raw = response;
639
+ return {
640
+ totalItems: raw.pagination.total_items ?? 0,
641
+ files: raw.files.map(normalizeFile)
642
+ };
643
+ }
644
+ // -----------------------------------------------------------------------
645
+ // Labels
646
+ // -----------------------------------------------------------------------
647
+ async addLabels(scanUuid, labels) {
648
+ await this.client.scans.addLabels(scanUuid, { labels });
649
+ }
650
+ async setLabels(scanUuid, labels) {
651
+ await this.client.scans.setLabels(scanUuid, { labels });
652
+ }
653
+ async deleteLabels(scanUuid, keys) {
654
+ await this.client.scans.deleteLabels(scanUuid, keys);
655
+ }
656
+ async getLabelKeys(opts) {
657
+ const response = await this.client.scans.getLabelKeys(opts);
658
+ const raw = response;
659
+ return {
660
+ totalItems: raw.pagination.total_items ?? 0,
661
+ keys: raw.keys
662
+ };
663
+ }
664
+ async getLabelValues(key, opts) {
665
+ const response = await this.client.scans.getLabelValues(key, opts);
666
+ const raw = response;
667
+ return {
668
+ totalItems: raw.pagination.total_items ?? 0,
669
+ values: raw.values
670
+ };
671
+ }
672
+ // -----------------------------------------------------------------------
673
+ // PyPI Auth
674
+ // -----------------------------------------------------------------------
675
+ async getPyPIAuth() {
676
+ const response = await this.client.getPyPIAuth();
677
+ const raw = response;
678
+ return {
679
+ url: raw.url,
680
+ expiresAt: raw.expires_at
681
+ };
682
+ }
683
+ };
684
+
685
+ // src/airs/promptsets.ts
686
+ import { RedTeamClient } from "@cdot65/prisma-airs-sdk";
687
+ function normalizePromptSet(raw) {
688
+ return {
689
+ uuid: raw.uuid,
690
+ name: raw.name,
691
+ active: raw.active,
692
+ archive: raw.archive,
693
+ description: raw.description,
694
+ createdAt: raw.created_at,
695
+ updatedAt: raw.updated_at
696
+ };
697
+ }
698
+ function normalizePrompt(raw) {
699
+ return {
700
+ uuid: raw.uuid,
701
+ prompt: raw.prompt,
702
+ goal: raw.goal,
703
+ active: raw.active,
704
+ promptSetId: raw.prompt_set_id
705
+ };
706
+ }
707
+ var SdkPromptSetService = class {
708
+ client;
709
+ constructor(opts) {
710
+ this.client = new RedTeamClient(opts);
711
+ }
712
+ async createPromptSet(name, description) {
713
+ const response = await this.client.customAttacks.createPromptSet({
714
+ name,
715
+ ...description ? { description } : {}
716
+ });
717
+ return { uuid: response.uuid, name: response.name };
718
+ }
719
+ async addPrompt(promptSetId, prompt, goal) {
720
+ const response = await this.client.customAttacks.createPrompt({
721
+ prompt,
722
+ prompt_set_id: promptSetId,
723
+ ...goal ? { goal } : {}
724
+ });
725
+ return { uuid: response.uuid, prompt: response.prompt };
726
+ }
727
+ async listPromptSets() {
728
+ const response = await this.client.customAttacks.listPromptSets();
729
+ return (response.data ?? []).map((ps) => ({
730
+ uuid: ps.uuid,
731
+ name: ps.name,
732
+ active: ps.active
733
+ }));
734
+ }
735
+ async getPromptSet(uuid) {
736
+ const response = await this.client.customAttacks.getPromptSet(uuid);
737
+ return normalizePromptSet(response);
738
+ }
739
+ async updatePromptSet(uuid, request) {
740
+ const response = await this.client.customAttacks.updatePromptSet(uuid, request);
741
+ return normalizePromptSet(response);
742
+ }
743
+ async archivePromptSet(uuid, archive) {
744
+ await this.client.customAttacks.archivePromptSet(uuid, { archive });
745
+ }
746
+ async getPromptSetVersionInfo(uuid) {
747
+ const response = await this.client.customAttacks.getPromptSetVersionInfo(uuid);
748
+ const raw = response;
749
+ return {
750
+ uuid: raw.uuid,
751
+ version: raw.version,
752
+ stats: raw.stats
753
+ };
754
+ }
755
+ /**
756
+ * Fetch a prompt set and its version info in one call, degrading gracefully when the
757
+ * version-info endpoint is unavailable. The upstream `/version-info` route currently
758
+ * returns 500 for every prompt set (see prisma-airs-cli#117); without this, a 500 there
759
+ * would abort the whole `prompt-sets get` command even though the set itself fetched fine.
760
+ * The set is always returned; `versionInfo` is `undefined` when that lookup fails.
761
+ */
762
+ async getPromptSetWithVersionInfo(uuid) {
763
+ const set = await this.getPromptSet(uuid);
764
+ let versionInfo;
765
+ try {
766
+ versionInfo = await this.getPromptSetVersionInfo(uuid);
767
+ } catch {
768
+ versionInfo = void 0;
769
+ }
770
+ return { set, versionInfo };
771
+ }
772
+ async downloadTemplate(uuid) {
773
+ return this.client.customAttacks.downloadTemplate(uuid);
774
+ }
775
+ async uploadPromptsCsv(uuid, file) {
776
+ const response = await this.client.customAttacks.uploadPromptsCsv(uuid, file);
777
+ return response;
778
+ }
779
+ async listPrompts(setUuid, opts) {
780
+ const response = await this.client.customAttacks.listPrompts(setUuid, opts);
781
+ return response.data.map(normalizePrompt);
782
+ }
783
+ async getPrompt(setUuid, promptUuid) {
784
+ const response = await this.client.customAttacks.getPrompt(setUuid, promptUuid);
785
+ return normalizePrompt(response);
786
+ }
787
+ async updatePrompt(setUuid, promptUuid, request) {
788
+ const response = await this.client.customAttacks.updatePrompt(
789
+ setUuid,
790
+ promptUuid,
791
+ request
792
+ );
793
+ return normalizePrompt(response);
794
+ }
795
+ async deletePrompt(setUuid, promptUuid) {
796
+ await this.client.customAttacks.deletePrompt(setUuid, promptUuid);
797
+ }
798
+ async getPropertyNames() {
799
+ const response = await this.client.customAttacks.getPropertyNames();
800
+ const raw = response;
801
+ return raw.data ?? [];
802
+ }
803
+ async createPropertyName(name) {
804
+ const response = await this.client.customAttacks.createPropertyName({ name });
805
+ return response;
806
+ }
807
+ async getPropertyValues(name) {
808
+ const response = await this.client.customAttacks.getPropertyValues(name);
809
+ const raw = response;
810
+ return { name: raw.name ?? name, values: raw.values ?? [] };
811
+ }
812
+ async createPropertyValue(name, value) {
813
+ const response = await this.client.customAttacks.createPropertyValue({
814
+ property_name: name,
815
+ property_value: value
816
+ });
817
+ return response;
818
+ }
819
+ };
820
+
821
+ // src/airs/redteam.ts
822
+ import { RedTeamClient as RedTeamClient2 } from "@cdot65/prisma-airs-sdk";
823
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["COMPLETED", "PARTIALLY_COMPLETE", "FAILED", "ABORTED"]);
824
+ var DEFAULT_DYNAMIC_BREADTH = 6;
825
+ var DEFAULT_DYNAMIC_DEPTH = 10;
826
+ function normalizeJob(raw) {
827
+ const target = raw.target;
828
+ return {
829
+ uuid: raw.uuid,
830
+ name: raw.name,
831
+ status: raw.status,
832
+ jobType: raw.job_type,
833
+ targetId: raw.target_id,
834
+ targetName: target?.name,
835
+ score: raw.score,
836
+ asr: raw.asr,
837
+ total: raw.total,
838
+ completed: raw.completed,
839
+ createdAt: raw.created_at
840
+ };
841
+ }
842
+ var REPORT_SUMMARY_TOKENS = {
843
+ "{{CRITICAL_RISK}}": "critical risk",
844
+ "{{HIGH_RISK}}": "high risk",
845
+ "{{MEDIUM_RISK}}": "medium risk",
846
+ "{{LOW_RISK}}": "low risk",
847
+ "{{INFORMATIONAL_RISK}}": "informational risk"
848
+ };
849
+ function interpolateReportSummary(summary) {
850
+ if (summary == null || summary === "") return summary;
851
+ let out = summary;
852
+ for (const [token, replacement] of Object.entries(REPORT_SUMMARY_TOKENS)) {
853
+ if (out.includes(token)) out = out.split(token).join(replacement);
854
+ }
855
+ return out;
856
+ }
857
+ function sanitizeTargetMetadata(metadata) {
858
+ if (!metadata) return metadata;
859
+ if (metadata.multi_turn === false && "multi_turn_error_message" in metadata) {
860
+ const { multi_turn_error_message: _drop, ...rest } = metadata;
861
+ return rest;
862
+ }
863
+ return metadata;
864
+ }
865
+ function normalizeTargetDetail(raw) {
866
+ return {
867
+ uuid: raw.uuid,
868
+ name: raw.name,
869
+ status: raw.status,
870
+ targetType: raw.target_type,
871
+ active: raw.active,
872
+ connectionType: raw.connection_type,
873
+ apiEndpointType: raw.api_endpoint_type,
874
+ responseMode: raw.response_mode,
875
+ authType: raw.auth_type,
876
+ authConfig: raw.auth_config,
877
+ networkBrokerChannelUuid: raw.network_broker_channel_uuid,
878
+ sessionSupported: raw.session_supported,
879
+ extraInfo: raw.extra_info,
880
+ description: raw.description,
881
+ connectionParams: raw.connection_params,
882
+ background: raw.target_background,
883
+ additionalContext: raw.additional_context,
884
+ metadata: sanitizeTargetMetadata(raw.target_metadata)
885
+ };
886
+ }
887
+ var SdkRedTeamService = class {
888
+ client;
889
+ constructor(opts) {
890
+ this.client = new RedTeamClient2(opts);
891
+ }
892
+ async getEulaContent() {
893
+ const response = await this.client.eula.getContent();
894
+ return { content: response.content };
895
+ }
896
+ async getEulaStatus() {
897
+ const raw = await this.client.eula.getStatus();
898
+ return {
899
+ isAccepted: raw.is_accepted,
900
+ acceptedAt: raw.accepted_at,
901
+ acceptedByUserId: raw.accepted_by_user_id
902
+ };
903
+ }
904
+ async acceptEula(eulaContent) {
905
+ const raw = await this.client.eula.accept({
906
+ eula_content: eulaContent,
907
+ accepted_at: (/* @__PURE__ */ new Date()).toISOString()
908
+ });
909
+ return {
910
+ isAccepted: raw.is_accepted,
911
+ acceptedAt: raw.accepted_at,
912
+ acceptedByUserId: raw.accepted_by_user_id
913
+ };
914
+ }
915
+ async createInstance(request) {
916
+ const raw = await this.client.instances.createInstance({
917
+ tsg_id: request.tsgId,
918
+ tenant_id: request.tenantId,
919
+ app_id: request.appId,
920
+ region: request.region
921
+ });
922
+ return {
923
+ tsgId: raw.tsg_id,
924
+ tenantId: raw.tenant_id,
925
+ appId: raw.app_id,
926
+ isSuccess: raw.is_success
927
+ };
928
+ }
929
+ async getInstance(tenantId) {
930
+ const raw = await this.client.instances.getInstance(tenantId);
931
+ return {
932
+ tsgId: raw.tsg_id,
933
+ tenantId: raw.tenant_id,
934
+ appId: raw.app_id,
935
+ region: raw.region
936
+ };
937
+ }
938
+ async updateInstance(tenantId, request) {
939
+ const raw = await this.client.instances.updateInstance(tenantId, {
940
+ tsg_id: request.tsgId,
941
+ tenant_id: request.tenantId,
942
+ app_id: request.appId,
943
+ region: request.region
944
+ });
945
+ return {
946
+ tsgId: raw.tsg_id,
947
+ tenantId: raw.tenant_id,
948
+ appId: raw.app_id,
949
+ isSuccess: raw.is_success
950
+ };
951
+ }
952
+ async deleteInstance(tenantId) {
953
+ const raw = await this.client.instances.deleteInstance(tenantId);
954
+ return {
955
+ tsgId: raw.tsg_id,
956
+ tenantId: raw.tenant_id,
957
+ appId: raw.app_id,
958
+ isSuccess: raw.is_success
959
+ };
960
+ }
961
+ async createDevices(tenantId, request) {
962
+ return await this.client.instances.createDevices(tenantId, request);
963
+ }
964
+ async updateDevices(tenantId, request) {
965
+ return await this.client.instances.updateDevices(tenantId, request);
966
+ }
967
+ async deleteDevices(tenantId, serialNumbers) {
968
+ return await this.client.instances.deleteDevices(tenantId, serialNumbers);
969
+ }
970
+ async getRegistryCredentials() {
971
+ const raw = await this.client.instances.getRegistryCredentials();
972
+ return {
973
+ token: raw.token,
974
+ expiry: raw.expiry
975
+ };
976
+ }
977
+ async validateTargetAuth(request) {
978
+ const sdkRequest = {
979
+ auth_type: request.authType,
980
+ auth_config: request.authConfig
981
+ };
982
+ if (request.targetId) sdkRequest.target_id = request.targetId;
983
+ const raw = await this.client.targets.validateAuth(sdkRequest);
984
+ return {
985
+ validated: raw.validated,
986
+ tokenPreview: raw.token_preview,
987
+ expiresIn: raw.expires_in
988
+ };
989
+ }
990
+ async getTargetMetadata() {
991
+ return await this.client.targets.getTargetMetadata();
992
+ }
993
+ async getTargetTemplates() {
994
+ return await this.client.targets.getTargetTemplates();
995
+ }
996
+ async listTargets() {
997
+ const all = [];
998
+ let skip = 0;
999
+ const limit = 100;
1000
+ for (; ; ) {
1001
+ const response = this.client.targets.list({ skip, limit });
1002
+ const body = await response;
1003
+ const data = body.data;
1004
+ for (const t of data) {
1005
+ all.push({
1006
+ uuid: t.uuid,
1007
+ name: t.name,
1008
+ status: t.status,
1009
+ targetType: t.target_type,
1010
+ active: t.active
1011
+ });
1012
+ }
1013
+ const pagination = body.pagination;
1014
+ if (!pagination || all.length >= (pagination.total ?? data.length) || data.length < limit) {
1015
+ break;
1016
+ }
1017
+ skip += limit;
1018
+ }
1019
+ return all;
1020
+ }
1021
+ async getTarget(uuid) {
1022
+ const response = await this.client.targets.get(uuid);
1023
+ return normalizeTargetDetail(response);
1024
+ }
1025
+ async createTarget(request, opts) {
1026
+ const response = await this.client.targets.create(request, opts);
1027
+ return normalizeTargetDetail(response);
1028
+ }
1029
+ async updateTarget(uuid, request, opts) {
1030
+ const response = await this.client.targets.update(uuid, request, opts);
1031
+ return normalizeTargetDetail(response);
1032
+ }
1033
+ async deleteTarget(uuid) {
1034
+ await this.client.targets.delete(uuid);
1035
+ }
1036
+ async probeTarget(request) {
1037
+ const response = await this.client.targets.probe(request);
1038
+ const raw = response;
1039
+ const meta = raw.target_metadata;
1040
+ if (meta && typeof meta === "object") {
1041
+ raw.target_metadata = sanitizeTargetMetadata(meta);
1042
+ }
1043
+ return raw;
1044
+ }
1045
+ async getTargetProfile(uuid) {
1046
+ const response = await this.client.targets.getProfile(uuid);
1047
+ return response;
1048
+ }
1049
+ async updateTargetProfile(uuid, request) {
1050
+ const response = await this.client.targets.updateProfile(uuid, request);
1051
+ return response;
1052
+ }
1053
+ async createScan(request) {
1054
+ let jobMetadata = {};
1055
+ if (request.jobType === "STATIC" && request.categories) {
1056
+ jobMetadata = { categories: request.categories };
1057
+ } else if (request.jobType === "CUSTOM" && request.customPromptSets) {
1058
+ jobMetadata = {
1059
+ custom_prompt_sets: request.customPromptSets
1060
+ };
1061
+ } else if (request.jobType === "DYNAMIC") {
1062
+ jobMetadata = {
1063
+ stream_breadth: request.streamBreadth ?? DEFAULT_DYNAMIC_BREADTH,
1064
+ stream_depth: request.streamDepth ?? DEFAULT_DYNAMIC_DEPTH,
1065
+ ...request.attackGoals?.length ? { attack_goals: request.attackGoals } : {}
1066
+ };
1067
+ }
1068
+ const response = await this.client.scans.create({
1069
+ name: request.name,
1070
+ target: { uuid: request.targetUuid },
1071
+ job_type: request.jobType,
1072
+ job_metadata: jobMetadata
1073
+ });
1074
+ return normalizeJob(response);
1075
+ }
1076
+ async getScan(jobId) {
1077
+ const response = await this.client.scans.get(jobId);
1078
+ return normalizeJob(response);
1079
+ }
1080
+ async listScans(opts) {
1081
+ const sdkOpts = {};
1082
+ if (opts?.status) sdkOpts.status = opts.status;
1083
+ if (opts?.jobType) sdkOpts.job_type = opts.jobType;
1084
+ if (opts?.targetId) sdkOpts.target_id = opts.targetId;
1085
+ if (opts?.limit) sdkOpts.limit = opts.limit;
1086
+ const response = await this.client.scans.list(sdkOpts);
1087
+ return response.data.map(
1088
+ normalizeJob
1089
+ );
1090
+ }
1091
+ async abortScan(jobId) {
1092
+ await this.client.scans.abort(jobId);
1093
+ }
1094
+ async getStaticReport(jobId) {
1095
+ const raw = await this.client.reports.getStaticReport(jobId);
1096
+ const severityReport = raw.severity_report;
1097
+ const stats = severityReport?.stats ?? [];
1098
+ const securityReport = raw.security_report;
1099
+ const subCategories = securityReport?.sub_categories ?? [];
1100
+ return {
1101
+ score: raw.score,
1102
+ asr: raw.asr,
1103
+ severityBreakdown: stats.map((s) => ({
1104
+ severity: s.severity,
1105
+ successful: s.successful ?? 0,
1106
+ failed: s.failed ?? 0
1107
+ })),
1108
+ reportSummary: interpolateReportSummary(raw.report_summary),
1109
+ categories: subCategories.map((sc) => {
1110
+ const successful = sc.successful ?? 0;
1111
+ const failed = sc.failed ?? 0;
1112
+ const total = sc.total ?? successful + failed;
1113
+ return {
1114
+ id: sc.id,
1115
+ displayName: sc.display_name,
1116
+ asr: total > 0 ? successful / total * 100 : 0,
1117
+ successful,
1118
+ failed,
1119
+ total
1120
+ };
1121
+ })
1122
+ };
1123
+ }
1124
+ async getDynamicReport(jobId) {
1125
+ const raw = await this.client.reports.getDynamicReport(jobId);
1126
+ return {
1127
+ score: raw.score,
1128
+ asr: raw.asr,
1129
+ totalGoals: raw.total_goals,
1130
+ goalsAchieved: raw.goals_achieved,
1131
+ totalStreams: raw.total_streams,
1132
+ totalThreats: raw.total_threats,
1133
+ reportSummary: interpolateReportSummary(raw.report_summary)
1134
+ };
1135
+ }
1136
+ async getCustomReport(jobId) {
1137
+ const raw = await this.client.customAttackReports.getReport(jobId);
1138
+ const reports = raw.custom_attack_reports ?? [];
1139
+ return {
1140
+ totalPrompts: raw.total_prompts,
1141
+ totalAttacks: raw.total_attacks,
1142
+ totalThreats: raw.total_threats,
1143
+ failedAttacks: raw.failed_attacks,
1144
+ score: raw.score,
1145
+ asr: raw.asr,
1146
+ promptSets: reports.map((r) => ({
1147
+ promptSetId: r.prompt_set_id,
1148
+ promptSetName: r.prompt_set_name,
1149
+ totalPrompts: r.total_prompts,
1150
+ totalAttacks: r.total_attacks,
1151
+ totalThreats: r.total_threats,
1152
+ threatRate: r.threat_rate
1153
+ }))
1154
+ };
1155
+ }
1156
+ async listAttacks(jobId, opts) {
1157
+ const response = await this.client.reports.listAttacks(jobId, opts);
1158
+ const data = response.data ?? [];
1159
+ const pagination = response.pagination;
1160
+ return {
1161
+ attacks: data.map((a) => ({
1162
+ id: a.uuid,
1163
+ name: a.attack_name,
1164
+ severity: a.severity,
1165
+ category: a.category,
1166
+ subCategory: a.sub_category,
1167
+ subCategoryDisplayName: a.sub_category_display_name,
1168
+ successful: a.threat ?? false
1169
+ })),
1170
+ totalItems: pagination?.total_items
1171
+ };
1172
+ }
1173
+ async listCustomAttacks(jobId, opts) {
1174
+ const response = await this.client.customAttackReports.listCustomAttacks(jobId, opts);
1175
+ return response.data.map(
1176
+ (a) => ({
1177
+ promptId: a.prompt_id,
1178
+ promptText: a.prompt_text,
1179
+ goal: a.goal,
1180
+ threat: a.threat ?? false,
1181
+ asr: a.asr,
1182
+ promptSetName: a.prompt_set_name
1183
+ })
1184
+ );
1185
+ }
1186
+ async getCategories() {
1187
+ const response = await this.client.scans.getCategories();
1188
+ return response.map((c) => ({
1189
+ id: c.id,
1190
+ displayName: c.display_name,
1191
+ description: c.description,
1192
+ subCategories: (c.sub_categories ?? []).map((sc) => ({
1193
+ id: sc.id,
1194
+ displayName: sc.display_name,
1195
+ description: sc.description
1196
+ }))
1197
+ }));
1198
+ }
1199
+ async waitForCompletion(jobId, onProgress, intervalMs = 5e3) {
1200
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1201
+ while (true) {
1202
+ const job = await this.getScan(jobId);
1203
+ onProgress?.(job);
1204
+ if (job.status === "FAILED") {
1205
+ throw new Error(`Scan ${jobId} failed`);
1206
+ }
1207
+ if (TERMINAL_STATUSES.has(job.status)) {
1208
+ return job;
1209
+ }
1210
+ await delay(intervalMs);
1211
+ }
1212
+ }
1213
+ };
1214
+
1215
+ // src/airs/runtime.ts
1216
+ import { Content, init, Scanner } from "@cdot65/prisma-airs-sdk";
1217
+ var BATCH_SIZE = 5;
1218
+ var DEFAULT_POLL_INTERVAL_MS = 5e3;
1219
+ var DEFAULT_MAX_RETRIES = 5;
1220
+ var DEFAULT_BASE_DELAY_MS = 1e4;
1221
+ function isRateLimitError(err) {
1222
+ if (err instanceof Error) {
1223
+ const msg = err.message.toLowerCase();
1224
+ return msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("429");
1225
+ }
1226
+ return false;
1227
+ }
1228
+ var SdkRuntimeService = class {
1229
+ scanner;
1230
+ constructor(opts) {
1231
+ init(opts);
1232
+ this.scanner = new Scanner();
1233
+ }
1234
+ async scanPrompt(profileName, prompt, response) {
1235
+ const contentOpts = { prompt };
1236
+ if (response) contentOpts.response = response;
1237
+ const content = new Content(contentOpts);
1238
+ const res = await this.scanner.syncScan({ profile_name: profileName }, content, void 0);
1239
+ const detected = res.prompt_detected ?? {};
1240
+ const triggered = !!(detected.topic_violation || detected.injection || detected.toxic_content || detected.dlp || detected.url_cats || detected.malicious_code);
1241
+ return {
1242
+ prompt,
1243
+ response,
1244
+ scanId: res.scan_id ?? "",
1245
+ reportId: res.report_id ?? "",
1246
+ action: res.action === "block" ? "block" : "allow",
1247
+ category: res.category ?? "unknown",
1248
+ triggered,
1249
+ detections: detected
1250
+ };
1251
+ }
1252
+ async submitBulkScan(profileName, prompts, sessionId) {
1253
+ const scanIds = [];
1254
+ for (let i = 0; i < prompts.length; i += BATCH_SIZE) {
1255
+ const batch = prompts.slice(i, i + BATCH_SIZE);
1256
+ const scanObjects = batch.map((prompt, idx) => ({
1257
+ req_id: i + idx,
1258
+ scan_req: {
1259
+ ai_profile: { profile_name: profileName },
1260
+ contents: [{ prompt }],
1261
+ ...sessionId ? { session_id: sessionId } : {}
1262
+ }
1263
+ }));
1264
+ const res = await this.scanner.asyncScan(scanObjects);
1265
+ scanIds.push(res.scan_id);
1266
+ }
1267
+ return scanIds;
1268
+ }
1269
+ /**
1270
+ * Poll async scan results until all complete or fail.
1271
+ *
1272
+ * Note: The async query API (`queryByScanIds`) does not return `prompt`,
1273
+ * `response`, `triggered`, or `detections` fields. These are set to
1274
+ * defaults (`''`, `undefined`, `false`, `{}`) in the returned results.
1275
+ * Use `scanPrompt()` (sync API) when these fields are needed.
1276
+ */
1277
+ async pollResults(scanIds, intervalMs = DEFAULT_POLL_INTERVAL_MS, retryOpts) {
1278
+ const maxRetries = retryOpts?.maxRetries ?? DEFAULT_MAX_RETRIES;
1279
+ const baseDelay = retryOpts?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;
1280
+ const completed = /* @__PURE__ */ new Map();
1281
+ const pending = new Set(scanIds);
1282
+ let retryLevel = 0;
1283
+ while (pending.size > 0) {
1284
+ const pendingIds = [...pending];
1285
+ let sweepCompleted = true;
1286
+ for (let b = 0; b < pendingIds.length; b += 5) {
1287
+ const batch = pendingIds.slice(b, b + 5);
1288
+ let results;
1289
+ try {
1290
+ results = await this.scanner.queryByScanIds(batch);
1291
+ } catch (err) {
1292
+ if (isRateLimitError(err) && retryLevel < maxRetries) {
1293
+ retryLevel++;
1294
+ const delayMs = baseDelay * 2 ** (retryLevel - 1);
1295
+ retryOpts?.onRetry?.(retryLevel, delayMs);
1296
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1297
+ sweepCompleted = false;
1298
+ break;
1299
+ }
1300
+ throw err;
1301
+ }
1302
+ this.processQueryResults(results, completed, pending);
1303
+ if (b + 5 < pendingIds.length) {
1304
+ const batchDelay = retryLevel > 0 ? baseDelay : Math.min(baseDelay, 1e3);
1305
+ await new Promise((resolve) => setTimeout(resolve, batchDelay));
1306
+ }
1307
+ }
1308
+ if (sweepCompleted && retryLevel > 0) {
1309
+ retryLevel = Math.max(0, retryLevel - 1);
1310
+ }
1311
+ if (pending.size > 0) {
1312
+ const sweepDelay = retryLevel > 0 ? baseDelay * 2 ** retryLevel : intervalMs;
1313
+ await new Promise((resolve) => setTimeout(resolve, sweepDelay));
1314
+ }
1315
+ }
1316
+ return scanIds.map((id) => completed.get(id));
1317
+ }
1318
+ processQueryResults(results, completed, pending) {
1319
+ for (const r of results) {
1320
+ const id = r.scan_id ?? "";
1321
+ const status = (r.status ?? "").toLowerCase();
1322
+ if ((status === "complete" || status === "completed") && r.result) {
1323
+ const result = r.result;
1324
+ completed.set(id, {
1325
+ prompt: "",
1326
+ // not available from async API
1327
+ response: void 0,
1328
+ // not available from async API
1329
+ scanId: result.scan_id ?? id,
1330
+ reportId: result.report_id ?? "",
1331
+ action: result.action === "block" ? "block" : "allow",
1332
+ category: result.category ?? "unknown",
1333
+ triggered: false,
1334
+ // not available from async API — always false
1335
+ detections: {}
1336
+ // not available from async API
1337
+ });
1338
+ pending.delete(id);
1339
+ } else if (status === "failed") {
1340
+ completed.set(id, {
1341
+ prompt: "",
1342
+ // not available from async API
1343
+ response: void 0,
1344
+ // not available from async API
1345
+ scanId: id,
1346
+ reportId: "",
1347
+ action: "allow",
1348
+ // safe default for failed scans
1349
+ category: "error",
1350
+ triggered: false,
1351
+ // not available from async API — always false
1352
+ detections: {}
1353
+ // not available from async API
1354
+ });
1355
+ pending.delete(id);
1356
+ }
1357
+ }
1358
+ }
1359
+ static formatResultsCsv(results) {
1360
+ const header = "prompt,action,category,triggered,scan_id,report_id";
1361
+ const rows = results.map((r) => {
1362
+ const escaped = r.prompt.replace(/"/g, '""');
1363
+ return `"${escaped}","${r.action}","${r.category}","${r.triggered}","${r.scanId}","${r.reportId}"`;
1364
+ });
1365
+ return [header, ...rows].join("\n");
1366
+ }
1367
+ };
1368
+
1369
+ // src/airs/scanner.ts
1370
+ import * as fs from "fs/promises";
1371
+ import { Content as Content2, init as init2, Scanner as Scanner2 } from "@cdot65/prisma-airs-sdk";
1372
+ import pLimit from "p-limit";
1373
+ var AirsScanService = class {
1374
+ scanner;
1375
+ constructor(opts) {
1376
+ init2(opts);
1377
+ this.scanner = new Scanner2();
1378
+ }
1379
+ /** Scan a single prompt synchronously and return the normalized result. */
1380
+ async scan(profileName, prompt, sessionId) {
1381
+ const content = new Content2({ prompt });
1382
+ const response = await this.scanner.syncScan(
1383
+ { profile_name: profileName },
1384
+ content,
1385
+ sessionId ? { sessionId } : void 0
1386
+ );
1387
+ const action = response.action === "block" ? "block" : "allow";
1388
+ const detected = response.prompt_detected;
1389
+ const triggered = detected?.topic_violation === true;
1390
+ const category = response.category ?? void 0;
1391
+ return {
1392
+ scanId: response.scan_id ?? "",
1393
+ reportId: response.report_id ?? "",
1394
+ action,
1395
+ triggered,
1396
+ category,
1397
+ raw: response
1398
+ };
1399
+ }
1400
+ /** Scan multiple prompts concurrently (default 5) and return results in order. */
1401
+ async scanBatch(profileName, prompts, concurrency = 5, sessionId) {
1402
+ const limit = pLimit(concurrency);
1403
+ return Promise.all(
1404
+ prompts.map((prompt) => limit(() => this.scan(profileName, prompt, sessionId)))
1405
+ );
1406
+ }
1407
+ };
1408
+ var RateLimitedScanService = class {
1409
+ constructor(inner, maxPerSecond) {
1410
+ this.inner = inner;
1411
+ this.maxPerSecond = maxPerSecond;
1412
+ }
1413
+ timestamps = [];
1414
+ async acquireToken() {
1415
+ const now = Date.now();
1416
+ this.timestamps = this.timestamps.filter((t) => now - t < 1e3);
1417
+ if (this.timestamps.length >= this.maxPerSecond) {
1418
+ const oldest = this.timestamps[0];
1419
+ const waitMs = 1e3 - (now - oldest);
1420
+ if (waitMs > 0) {
1421
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
1422
+ }
1423
+ const after = Date.now();
1424
+ this.timestamps = this.timestamps.filter((t) => after - t < 1e3);
1425
+ }
1426
+ this.timestamps.push(Date.now());
1427
+ }
1428
+ async scan(profileName, prompt, sessionId) {
1429
+ await this.acquireToken();
1430
+ return this.inner.scan(profileName, prompt, sessionId);
1431
+ }
1432
+ async scanBatch(profileName, prompts, concurrency, sessionId) {
1433
+ const limit = pLimit(concurrency ?? 5);
1434
+ return Promise.all(
1435
+ prompts.map((prompt) => limit(() => this.scan(profileName, prompt, sessionId)))
1436
+ );
1437
+ }
1438
+ };
1439
+
1440
+ // src/backup/io.ts
1441
+ import fs2 from "fs";
1442
+ import path from "path";
1443
+ import yaml from "js-yaml";
1444
+ function sanitizeFilename(name) {
1445
+ if (!name) return "unnamed";
1446
+ const sanitized = name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
1447
+ return sanitized || "unnamed";
1448
+ }
1449
+ function resolveOutputDir(userDir, defaultSubdir) {
1450
+ if (userDir) return path.resolve(userDir);
1451
+ return path.resolve("./airs-backup", defaultSubdir);
1452
+ }
1453
+ function writeBackupFile(dir, filename, envelope, format) {
1454
+ fs2.mkdirSync(dir, { recursive: true });
1455
+ const ext = format === "yaml" ? "yaml" : "json";
1456
+ const filePath = path.join(dir, `${filename}.${ext}`);
1457
+ const content = format === "yaml" ? yaml.dump(envelope, { lineWidth: -1, noRefs: true }) : `${JSON.stringify(envelope, null, 2)}
1458
+ `;
1459
+ fs2.writeFileSync(filePath, content, "utf-8");
1460
+ }
1461
+ function readBackupFile(filePath) {
1462
+ const ext = path.extname(filePath).toLowerCase();
1463
+ if (ext !== ".json" && ext !== ".yaml" && ext !== ".yml") {
1464
+ throw new Error(`Unsupported file format: ${ext} (expected .json, .yaml, or .yml)`);
1465
+ }
1466
+ const raw = fs2.readFileSync(filePath, "utf-8");
1467
+ const parsed = ext === ".json" ? JSON.parse(raw) : yaml.load(raw);
1468
+ if (!parsed || typeof parsed !== "object" || !("version" in parsed) || !("data" in parsed)) {
1469
+ throw new Error(`Invalid backup file: ${filePath} (missing version or data)`);
1470
+ }
1471
+ return parsed;
1472
+ }
1473
+ function readBackupDir(dirPath, resourceType) {
1474
+ const files = fs2.readdirSync(dirPath).filter((f) => /\.(json|ya?ml)$/i.test(f)).map((f) => path.join(dirPath, f));
1475
+ const envelopes = [];
1476
+ for (const filePath of files) {
1477
+ try {
1478
+ const envelope = readBackupFile(filePath);
1479
+ if (envelope.resourceType === resourceType) {
1480
+ envelopes.push(envelope);
1481
+ }
1482
+ } catch {
1483
+ }
1484
+ }
1485
+ return envelopes;
1486
+ }
1487
+
1488
+ // src/config/loader.ts
1489
+ import { readFile } from "fs/promises";
1490
+ import { homedir } from "os";
1491
+ import { join } from "path";
1492
+
1493
+ // src/config/schema.ts
1494
+ import { z } from "zod";
1495
+ var ConfigSchema = z.object({
1496
+ // AIRS Scanner (runtime scan API)
1497
+ airsApiKey: z.string().optional(),
1498
+ airsApiToken: z.string().optional(),
1499
+ airsApiEndpoint: z.string().optional(),
1500
+ airsNumRetries: z.coerce.number().int().min(0).max(5).optional(),
1501
+ // AIRS Management (SDK v2 — OAuth2 client credentials)
1502
+ mgmtClientId: z.string().optional(),
1503
+ mgmtClientSecret: z.string().optional(),
1504
+ mgmtTsgId: z.string().optional(),
1505
+ mgmtEndpoint: z.string().optional(),
1506
+ mgmtTokenEndpoint: z.string().optional(),
1507
+ dlpEndpoint: z.string().optional(),
1508
+ // Red Team (endpoints only; creds shared with mgmt*)
1509
+ redTeamDataEndpoint: z.string().optional(),
1510
+ redTeamMgmtEndpoint: z.string().optional(),
1511
+ redTeamTokenEndpoint: z.string().optional(),
1512
+ // Model Security (endpoints only; creds shared with mgmt*)
1513
+ modelSecDataEndpoint: z.string().optional(),
1514
+ modelSecMgmtEndpoint: z.string().optional(),
1515
+ modelSecTokenEndpoint: z.string().optional(),
1516
+ // Tuning
1517
+ scanConcurrency: z.coerce.number().int().min(1).max(20).default(5),
1518
+ // Persistence
1519
+ dataDir: z.string().default("~/.prisma-airs/runs")
1520
+ });
1521
+
1522
+ // src/config/loader.ts
1523
+ function expandHome(p) {
1524
+ return p.startsWith("~") ? join(homedir(), p.slice(1)) : p;
1525
+ }
1526
+ function fromEnv() {
1527
+ const env = process.env;
1528
+ return {
1529
+ airsApiKey: env.PANW_AI_SEC_API_KEY,
1530
+ airsApiToken: env.PANW_AI_SEC_API_TOKEN,
1531
+ airsApiEndpoint: env.PANW_AI_SEC_API_ENDPOINT,
1532
+ airsNumRetries: env.PANW_AI_SEC_NUM_RETRIES,
1533
+ mgmtClientId: env.PANW_MGMT_CLIENT_ID,
1534
+ mgmtClientSecret: env.PANW_MGMT_CLIENT_SECRET,
1535
+ mgmtTsgId: env.PANW_MGMT_TSG_ID,
1536
+ mgmtEndpoint: env.PANW_MGMT_ENDPOINT,
1537
+ mgmtTokenEndpoint: env.PANW_MGMT_TOKEN_ENDPOINT,
1538
+ dlpEndpoint: env.PANW_DLP_ENDPOINT,
1539
+ redTeamDataEndpoint: env.PANW_RED_TEAM_DATA_ENDPOINT,
1540
+ redTeamMgmtEndpoint: env.PANW_RED_TEAM_MGMT_ENDPOINT,
1541
+ redTeamTokenEndpoint: env.PANW_RED_TEAM_TOKEN_ENDPOINT,
1542
+ modelSecDataEndpoint: env.PANW_MODEL_SEC_DATA_ENDPOINT,
1543
+ modelSecMgmtEndpoint: env.PANW_MODEL_SEC_MGMT_ENDPOINT,
1544
+ modelSecTokenEndpoint: env.PANW_MODEL_SEC_TOKEN_ENDPOINT,
1545
+ scanConcurrency: env.SCAN_CONCURRENCY,
1546
+ dataDir: env.DATA_DIR
1547
+ };
1548
+ }
1549
+ async function fromFile(path2) {
1550
+ try {
1551
+ const data = await readFile(path2, "utf-8");
1552
+ return JSON.parse(data);
1553
+ } catch {
1554
+ return {};
1555
+ }
1556
+ }
1557
+ function stripUndefined(obj) {
1558
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0 && v !== ""));
1559
+ }
1560
+ function resolveConfigFilePath(configFilePath) {
1561
+ if (configFilePath) return configFilePath;
1562
+ const envPath = process.env.PRISMA_AIRS_CONFIG_PATH;
1563
+ if (envPath) return expandHome(envPath);
1564
+ return join(homedir(), ".prisma-airs", "config.json");
1565
+ }
1566
+ async function loadConfig(cliOverrides = {}, configFilePath) {
1567
+ const filePath = resolveConfigFilePath(configFilePath);
1568
+ const fileConfig = await fromFile(filePath);
1569
+ const envConfig = fromEnv();
1570
+ const merged = {
1571
+ ...stripUndefined(fileConfig),
1572
+ ...stripUndefined(envConfig),
1573
+ ...stripUndefined(cliOverrides)
1574
+ };
1575
+ const config = ConfigSchema.parse(merged);
1576
+ return {
1577
+ ...config,
1578
+ dataDir: expandHome(config.dataDir)
1579
+ };
1580
+ }
1581
+ async function inspectConfig(configFilePath) {
1582
+ const filePath = resolveConfigFilePath(configFilePath);
1583
+ const fileConfig = stripUndefined(await fromFile(filePath));
1584
+ const envConfig = stripUndefined(fromEnv());
1585
+ const merged = { ...fileConfig, ...envConfig };
1586
+ const config = ConfigSchema.parse(merged);
1587
+ const entries = {};
1588
+ for (const key of Object.keys(ConfigSchema.shape)) {
1589
+ const source = key in envConfig ? "env" : key in fileConfig ? "file" : "default";
1590
+ entries[key] = { value: config[key], source };
1591
+ }
1592
+ return entries;
1593
+ }
1594
+
1595
+ // src/core/constraints.ts
1596
+ var MAX_NAME_LENGTH = 100;
1597
+ var MAX_DESCRIPTION_LENGTH = 250;
1598
+ var MAX_EXAMPLE_LENGTH = 250;
1599
+ var MAX_EXAMPLES = 5;
1600
+ var MIN_EXAMPLES = 2;
1601
+ var MAX_COMBINED_LENGTH = 1e3;
1602
+ function byteLen(s) {
1603
+ return Buffer.byteLength(s, "utf8");
1604
+ }
1605
+ function validateName(name) {
1606
+ const errors = [];
1607
+ if (!name || name.length === 0) {
1608
+ errors.push({ field: "name", message: "Name is required" });
1609
+ } else if (byteLen(name) > MAX_NAME_LENGTH) {
1610
+ errors.push({ field: "name", message: `Name must be at most ${MAX_NAME_LENGTH} bytes` });
1611
+ }
1612
+ return errors;
1613
+ }
1614
+ function validateDescription(description) {
1615
+ const errors = [];
1616
+ if (!description || description.length === 0) {
1617
+ errors.push({ field: "description", message: "Description is required" });
1618
+ } else if (byteLen(description) > MAX_DESCRIPTION_LENGTH) {
1619
+ errors.push({
1620
+ field: "description",
1621
+ message: `Description must be at most ${MAX_DESCRIPTION_LENGTH} bytes`
1622
+ });
1623
+ }
1624
+ return errors;
1625
+ }
1626
+ function validateExample(example, index) {
1627
+ const errors = [];
1628
+ if (!example || example.length === 0) {
1629
+ errors.push({ field: `examples[${index}]`, message: `Example ${index} is required` });
1630
+ } else if (byteLen(example) > MAX_EXAMPLE_LENGTH) {
1631
+ errors.push({
1632
+ field: `examples[${index}]`,
1633
+ message: `Example ${index} must be at most ${MAX_EXAMPLE_LENGTH} bytes`
1634
+ });
1635
+ }
1636
+ return errors;
1637
+ }
1638
+ function validateExamples(examples) {
1639
+ const errors = [];
1640
+ if (examples.length < MIN_EXAMPLES) {
1641
+ errors.push({
1642
+ field: "examples",
1643
+ message: `At least ${MIN_EXAMPLES} examples required`
1644
+ });
1645
+ }
1646
+ if (examples.length > MAX_EXAMPLES) {
1647
+ errors.push({
1648
+ field: "examples",
1649
+ message: `At most ${MAX_EXAMPLES} examples allowed`
1650
+ });
1651
+ }
1652
+ for (let i = 0; i < examples.length; i++) {
1653
+ errors.push(...validateExample(examples[i], i));
1654
+ }
1655
+ return errors;
1656
+ }
1657
+ function validateTopic(topic) {
1658
+ const errors = [];
1659
+ errors.push(...validateName(topic.name));
1660
+ errors.push(...validateDescription(topic.description));
1661
+ errors.push(...validateExamples(topic.examples));
1662
+ const combined = byteLen(topic.name) + byteLen(topic.description) + topic.examples.reduce((sum, ex) => sum + byteLen(ex), 0);
1663
+ if (combined > MAX_COMBINED_LENGTH) {
1664
+ errors.push({
1665
+ field: "topic",
1666
+ message: `Combined length (${combined}) exceeds ${MAX_COMBINED_LENGTH} bytes`
1667
+ });
1668
+ }
1669
+ return errors;
1670
+ }
1671
+
1672
+ // src/core/metrics.ts
1673
+ function computeMetrics(results) {
1674
+ let truePositives = 0;
1675
+ let trueNegatives = 0;
1676
+ let falsePositives = 0;
1677
+ let falseNegatives = 0;
1678
+ let regressionCount = 0;
1679
+ for (const r of results) {
1680
+ if (r.testCase.expectedTriggered && r.actualTriggered) truePositives++;
1681
+ else if (!r.testCase.expectedTriggered && !r.actualTriggered) trueNegatives++;
1682
+ else if (!r.testCase.expectedTriggered && r.actualTriggered) falsePositives++;
1683
+ else if (r.testCase.expectedTriggered && !r.actualTriggered) falseNegatives++;
1684
+ if (r.testCase.source === "regression" && !r.correct) regressionCount++;
1685
+ }
1686
+ const totalPositives = truePositives + falseNegatives;
1687
+ const totalNegatives = trueNegatives + falsePositives;
1688
+ const total = results.length;
1689
+ const truePositiveRate = totalPositives > 0 ? truePositives / totalPositives : 0;
1690
+ const trueNegativeRate = totalNegatives > 0 ? trueNegatives / totalNegatives : 0;
1691
+ const accuracy = total > 0 ? (truePositives + trueNegatives) / total : 0;
1692
+ const coverage = Math.min(truePositiveRate, trueNegativeRate);
1693
+ const precision = truePositives + falsePositives > 0 ? truePositives / (truePositives + falsePositives) : 0;
1694
+ const recall = truePositiveRate;
1695
+ const f1Score = precision + recall > 0 ? 2 * precision * recall / (precision + recall) : 0;
1696
+ return {
1697
+ truePositives,
1698
+ trueNegatives,
1699
+ falsePositives,
1700
+ falseNegatives,
1701
+ truePositiveRate,
1702
+ trueNegativeRate,
1703
+ accuracy,
1704
+ coverage,
1705
+ f1Score,
1706
+ regressionCount
1707
+ };
1708
+ }
1709
+ function computeCategoryBreakdown(results) {
1710
+ const map = /* @__PURE__ */ new Map();
1711
+ for (const r of results) {
1712
+ const cat = r.testCase.category;
1713
+ const entry = map.get(cat) ?? { total: 0, fp: 0, fn: 0 };
1714
+ entry.total++;
1715
+ if (!r.testCase.expectedTriggered && r.actualTriggered) entry.fp++;
1716
+ if (r.testCase.expectedTriggered && !r.actualTriggered) entry.fn++;
1717
+ map.set(cat, entry);
1718
+ }
1719
+ return [...map.entries()].map(([category, { total, fp, fn }]) => ({
1720
+ category,
1721
+ total,
1722
+ fp,
1723
+ fn,
1724
+ errorRate: total > 0 ? (fp + fn) / total : 0
1725
+ })).sort((a, b) => b.errorRate - a.errorRate);
1726
+ }
1727
+
1728
+ export {
1729
+ SdkManagementService,
1730
+ getOrCreateManagementClient,
1731
+ SdkModelSecurityService,
1732
+ SdkPromptSetService,
1733
+ SdkRedTeamService,
1734
+ SdkRuntimeService,
1735
+ AirsScanService,
1736
+ RateLimitedScanService,
1737
+ sanitizeFilename,
1738
+ resolveOutputDir,
1739
+ writeBackupFile,
1740
+ readBackupFile,
1741
+ readBackupDir,
1742
+ ConfigSchema,
1743
+ resolveConfigFilePath,
1744
+ loadConfig,
1745
+ inspectConfig,
1746
+ validateName,
1747
+ validateDescription,
1748
+ validateExamples,
1749
+ validateTopic,
1750
+ computeMetrics,
1751
+ computeCategoryBreakdown
1752
+ };