@mitre/hdf-converters 2.12.6 → 2.13.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 (370) hide show
  1. package/README.md +25 -24
  2. package/lib/data/converters/csv2json.d.ts +1 -0
  3. package/lib/data/converters/csv2json.d.ts.map +1 -0
  4. package/lib/data/converters/csv2json.js +1 -1
  5. package/lib/data/converters/csv2json.js.map +1 -1
  6. package/lib/data/converters/xml2json.d.ts +1 -0
  7. package/lib/data/converters/xml2json.d.ts.map +1 -0
  8. package/lib/data/converters/xml2json.js +6 -25
  9. package/lib/data/converters/xml2json.js.map +1 -1
  10. package/lib/data/reverse-html-mapper/convert-to-embedded-strings.d.ts +2 -0
  11. package/lib/data/reverse-html-mapper/convert-to-embedded-strings.d.ts.map +1 -0
  12. package/lib/data/reverse-html-mapper/convert-to-embedded-strings.js +13 -0
  13. package/lib/data/reverse-html-mapper/convert-to-embedded-strings.js.map +1 -0
  14. package/lib/index.d.ts +6 -0
  15. package/lib/index.d.ts.map +1 -0
  16. package/lib/index.js +23 -8
  17. package/lib/index.js.map +1 -1
  18. package/lib/package.json +19 -40
  19. package/lib/src/anchore-grype-mapper.d.ts +1 -0
  20. package/lib/src/anchore-grype-mapper.d.ts.map +1 -0
  21. package/lib/src/anchore-grype-mapper.js +7 -1
  22. package/lib/src/anchore-grype-mapper.js.map +1 -1
  23. package/lib/src/asff-mapper/asff-mapper.d.ts +1 -0
  24. package/lib/src/asff-mapper/asff-mapper.d.ts.map +1 -0
  25. package/lib/src/asff-mapper/asff-mapper.js +274 -237
  26. package/lib/src/asff-mapper/asff-mapper.js.map +1 -1
  27. package/lib/src/asff-mapper/case-cms-inspec.d.ts +1 -0
  28. package/lib/src/asff-mapper/case-cms-inspec.d.ts.map +1 -0
  29. package/lib/src/asff-mapper/case-cms-inspec.js +18 -9
  30. package/lib/src/asff-mapper/case-cms-inspec.js.map +1 -1
  31. package/lib/src/asff-mapper/case-firewall-manager.d.ts +1 -0
  32. package/lib/src/asff-mapper/case-firewall-manager.d.ts.map +1 -0
  33. package/lib/src/asff-mapper/case-firewall-manager.js +18 -9
  34. package/lib/src/asff-mapper/case-firewall-manager.js.map +1 -1
  35. package/lib/src/asff-mapper/case-guardduty.d.ts +1 -0
  36. package/lib/src/asff-mapper/case-guardduty.d.ts.map +1 -0
  37. package/lib/src/asff-mapper/case-guardduty.js +18 -9
  38. package/lib/src/asff-mapper/case-guardduty.js.map +1 -1
  39. package/lib/src/asff-mapper/case-inspector.d.ts +1 -0
  40. package/lib/src/asff-mapper/case-inspector.d.ts.map +1 -0
  41. package/lib/src/asff-mapper/case-inspector.js +18 -9
  42. package/lib/src/asff-mapper/case-inspector.js.map +1 -1
  43. package/lib/src/asff-mapper/case-previously-hdf.d.ts +1 -0
  44. package/lib/src/asff-mapper/case-previously-hdf.d.ts.map +1 -0
  45. package/lib/src/asff-mapper/case-previously-hdf.js +21 -10
  46. package/lib/src/asff-mapper/case-previously-hdf.js.map +1 -1
  47. package/lib/src/asff-mapper/case-prowler.d.ts +1 -0
  48. package/lib/src/asff-mapper/case-prowler.d.ts.map +1 -0
  49. package/lib/src/asff-mapper/case-prowler.js +19 -9
  50. package/lib/src/asff-mapper/case-prowler.js.map +1 -1
  51. package/lib/src/asff-mapper/case-security-hub.d.ts +1 -0
  52. package/lib/src/asff-mapper/case-security-hub.d.ts.map +1 -0
  53. package/lib/src/asff-mapper/case-security-hub.js +24 -9
  54. package/lib/src/asff-mapper/case-security-hub.js.map +1 -1
  55. package/lib/src/asff-mapper/case-trivy.d.ts +1 -0
  56. package/lib/src/asff-mapper/case-trivy.d.ts.map +1 -0
  57. package/lib/src/asff-mapper/case-trivy.js +18 -9
  58. package/lib/src/asff-mapper/case-trivy.js.map +1 -1
  59. package/lib/src/aws-config-mapper.d.ts +1 -0
  60. package/lib/src/aws-config-mapper.d.ts.map +1 -0
  61. package/lib/src/aws-config-mapper.js +29 -7
  62. package/lib/src/aws-config-mapper.js.map +1 -1
  63. package/lib/src/base-converter.d.ts +2 -1
  64. package/lib/src/base-converter.d.ts.map +1 -0
  65. package/lib/src/base-converter.js +46 -26
  66. package/lib/src/base-converter.js.map +1 -1
  67. package/lib/src/burpsuite-mapper.d.ts +7 -0
  68. package/lib/src/burpsuite-mapper.d.ts.map +1 -0
  69. package/lib/src/burpsuite-mapper.js +115 -88
  70. package/lib/src/burpsuite-mapper.js.map +1 -1
  71. package/lib/src/checkov-mapper.d.ts +67 -0
  72. package/lib/src/checkov-mapper.d.ts.map +1 -0
  73. package/lib/src/checkov-mapper.js +240 -0
  74. package/lib/src/checkov-mapper.js.map +1 -0
  75. package/lib/src/ckl-mapper/checklist-jsonix-converter.d.ts +17 -0
  76. package/lib/src/ckl-mapper/checklist-jsonix-converter.d.ts.map +1 -0
  77. package/lib/src/ckl-mapper/checklist-jsonix-converter.js +38 -4
  78. package/lib/src/ckl-mapper/checklist-jsonix-converter.js.map +1 -1
  79. package/lib/src/ckl-mapper/checklist-mapper.d.ts +35 -0
  80. package/lib/src/ckl-mapper/checklist-mapper.d.ts.map +1 -0
  81. package/lib/src/ckl-mapper/checklist-mapper.js +262 -151
  82. package/lib/src/ckl-mapper/checklist-mapper.js.map +1 -1
  83. package/lib/src/ckl-mapper/checklist-metadata-utils.d.ts +1 -0
  84. package/lib/src/ckl-mapper/checklist-metadata-utils.d.ts.map +1 -0
  85. package/lib/src/ckl-mapper/checklist-metadata-utils.js +32 -15
  86. package/lib/src/ckl-mapper/checklist-metadata-utils.js.map +1 -1
  87. package/lib/src/ckl-mapper/checklistJsonix.d.ts +6 -0
  88. package/lib/src/ckl-mapper/checklistJsonix.d.ts.map +1 -0
  89. package/lib/src/ckl-mapper/checklistJsonix.js +8 -8
  90. package/lib/src/ckl-mapper/checklistJsonix.js.map +1 -1
  91. package/lib/src/ckl-mapper/jsonixMapping.d.ts +5 -0
  92. package/lib/src/ckl-mapper/jsonixMapping.d.ts.map +1 -0
  93. package/lib/src/ckl-mapper/jsonixMapping.js +4 -0
  94. package/lib/src/ckl-mapper/jsonixMapping.js.map +1 -1
  95. package/lib/src/converters-from-hdf/asff/asff-types.d.ts +1 -0
  96. package/lib/src/converters-from-hdf/asff/asff-types.d.ts.map +1 -0
  97. package/lib/src/converters-from-hdf/asff/asff-types.js +1 -0
  98. package/lib/src/converters-from-hdf/asff/asff-types.js.map +1 -1
  99. package/lib/src/converters-from-hdf/asff/reverse-asff-mapper.d.ts +1 -0
  100. package/lib/src/converters-from-hdf/asff/reverse-asff-mapper.d.ts.map +1 -0
  101. package/lib/src/converters-from-hdf/asff/reverse-asff-mapper.js +110 -84
  102. package/lib/src/converters-from-hdf/asff/reverse-asff-mapper.js.map +1 -1
  103. package/lib/src/converters-from-hdf/asff/transformers.d.ts +1 -0
  104. package/lib/src/converters-from-hdf/asff/transformers.d.ts.map +1 -0
  105. package/lib/src/converters-from-hdf/asff/transformers.js +68 -38
  106. package/lib/src/converters-from-hdf/asff/transformers.js.map +1 -1
  107. package/lib/src/converters-from-hdf/caat/reverse-caat-mapper.d.ts +1 -0
  108. package/lib/src/converters-from-hdf/caat/reverse-caat-mapper.d.ts.map +1 -0
  109. package/lib/src/converters-from-hdf/caat/reverse-caat-mapper.js +54 -28
  110. package/lib/src/converters-from-hdf/caat/reverse-caat-mapper.js.map +1 -1
  111. package/lib/src/converters-from-hdf/html/embedded-assets.d.ts +4 -0
  112. package/lib/src/converters-from-hdf/html/embedded-assets.d.ts.map +1 -0
  113. package/lib/src/converters-from-hdf/html/embedded-assets.js +8 -0
  114. package/lib/src/converters-from-hdf/html/embedded-assets.js.map +1 -0
  115. package/lib/src/converters-from-hdf/html/html-types.d.ts +1 -0
  116. package/lib/src/converters-from-hdf/html/html-types.d.ts.map +1 -0
  117. package/lib/src/converters-from-hdf/html/html-types.js +1 -0
  118. package/lib/src/converters-from-hdf/html/html-types.js.map +1 -1
  119. package/lib/src/converters-from-hdf/html/reverse-html-mapper.d.ts +3 -2
  120. package/lib/src/converters-from-hdf/html/reverse-html-mapper.d.ts.map +1 -0
  121. package/lib/src/converters-from-hdf/html/reverse-html-mapper.js +151 -107
  122. package/lib/src/converters-from-hdf/html/reverse-html-mapper.js.map +1 -1
  123. package/lib/src/converters-from-hdf/reverse-any-base-converter.d.ts +1 -0
  124. package/lib/src/converters-from-hdf/reverse-any-base-converter.d.ts.map +1 -0
  125. package/lib/src/converters-from-hdf/reverse-any-base-converter.js +3 -0
  126. package/lib/src/converters-from-hdf/reverse-any-base-converter.js.map +1 -1
  127. package/lib/src/converters-from-hdf/reverse-base-converter.d.ts +1 -0
  128. package/lib/src/converters-from-hdf/reverse-base-converter.d.ts.map +1 -0
  129. package/lib/src/converters-from-hdf/reverse-base-converter.js +29 -9
  130. package/lib/src/converters-from-hdf/reverse-base-converter.js.map +1 -1
  131. package/lib/src/converters-from-hdf/splunk/reverse-splunk-mapper.d.ts +1 -0
  132. package/lib/src/converters-from-hdf/splunk/reverse-splunk-mapper.d.ts.map +1 -0
  133. package/lib/src/converters-from-hdf/splunk/reverse-splunk-mapper.js +39 -14
  134. package/lib/src/converters-from-hdf/splunk/reverse-splunk-mapper.js.map +1 -1
  135. package/lib/src/converters-from-hdf/xccdf/reverse-xccdf-mapper.d.ts +1 -0
  136. package/lib/src/converters-from-hdf/xccdf/reverse-xccdf-mapper.d.ts.map +1 -0
  137. package/lib/src/converters-from-hdf/xccdf/reverse-xccdf-mapper.js +32 -10
  138. package/lib/src/converters-from-hdf/xccdf/reverse-xccdf-mapper.js.map +1 -1
  139. package/lib/src/conveyor-mapper.d.ts +1 -0
  140. package/lib/src/conveyor-mapper.d.ts.map +1 -0
  141. package/lib/src/conveyor-mapper.js +85 -40
  142. package/lib/src/conveyor-mapper.js.map +1 -1
  143. package/lib/src/cyclonedx-sbom-mapper.d.ts +1 -0
  144. package/lib/src/cyclonedx-sbom-mapper.d.ts.map +1 -0
  145. package/lib/src/cyclonedx-sbom-mapper.js +368 -294
  146. package/lib/src/cyclonedx-sbom-mapper.js.map +1 -1
  147. package/lib/src/dbprotect-mapper.d.ts +1 -0
  148. package/lib/src/dbprotect-mapper.d.ts.map +1 -0
  149. package/lib/src/dbprotect-mapper.js +74 -63
  150. package/lib/src/dbprotect-mapper.js.map +1 -1
  151. package/lib/src/dependency-track-mapper.d.ts +1 -0
  152. package/lib/src/dependency-track-mapper.d.ts.map +1 -0
  153. package/lib/src/dependency-track-mapper.js +144 -130
  154. package/lib/src/dependency-track-mapper.js.map +1 -1
  155. package/lib/src/fortify-mapper.d.ts +7 -0
  156. package/lib/src/fortify-mapper.d.ts.map +1 -0
  157. package/lib/src/fortify-mapper.js +118 -92
  158. package/lib/src/fortify-mapper.js.map +1 -1
  159. package/lib/src/gosec-mapper.d.ts +1 -0
  160. package/lib/src/gosec-mapper.d.ts.map +1 -0
  161. package/lib/src/gosec-mapper.js +90 -72
  162. package/lib/src/gosec-mapper.js.map +1 -1
  163. package/lib/src/ionchannel-mapper.d.ts +1 -0
  164. package/lib/src/ionchannel-mapper.d.ts.map +1 -0
  165. package/lib/src/ionchannel-mapper.js +130 -110
  166. package/lib/src/ionchannel-mapper.js.map +1 -1
  167. package/lib/src/jfrog-xray-mapper.d.ts +1 -0
  168. package/lib/src/jfrog-xray-mapper.d.ts.map +1 -0
  169. package/lib/src/jfrog-xray-mapper.js +92 -78
  170. package/lib/src/jfrog-xray-mapper.js.map +1 -1
  171. package/lib/src/jsonix-converter.d.ts +1 -0
  172. package/lib/src/jsonix-converter.d.ts.map +1 -0
  173. package/lib/src/jsonix-converter.js +1 -0
  174. package/lib/src/jsonix-converter.js.map +1 -1
  175. package/lib/src/jsonix-intermediate-converter.d.ts +1 -0
  176. package/lib/src/jsonix-intermediate-converter.d.ts.map +1 -0
  177. package/lib/src/jsonix-intermediate-converter.js.map +1 -1
  178. package/lib/src/mappings/AwsConfigMapping.d.ts +1 -0
  179. package/lib/src/mappings/AwsConfigMapping.d.ts.map +1 -0
  180. package/lib/src/mappings/AwsConfigMapping.js +19 -9
  181. package/lib/src/mappings/AwsConfigMapping.js.map +1 -1
  182. package/lib/src/mappings/AwsConfigMappingData.d.ts +1 -0
  183. package/lib/src/mappings/AwsConfigMappingData.d.ts.map +1 -0
  184. package/lib/src/mappings/AwsConfigMappingData.js.map +1 -1
  185. package/lib/src/mappings/CciNistMapping.d.ts +1 -0
  186. package/lib/src/mappings/CciNistMapping.d.ts.map +1 -0
  187. package/lib/src/mappings/CciNistMapping.js +4 -0
  188. package/lib/src/mappings/CciNistMapping.js.map +1 -1
  189. package/lib/src/mappings/CciNistMappingData.d.ts +1 -0
  190. package/lib/src/mappings/CciNistMappingData.d.ts.map +1 -0
  191. package/lib/src/mappings/CciNistMappingData.js.map +1 -1
  192. package/lib/src/mappings/CciNistMappingItem.d.ts +1 -0
  193. package/lib/src/mappings/CciNistMappingItem.d.ts.map +1 -0
  194. package/lib/src/mappings/CciNistMappingItem.js +2 -0
  195. package/lib/src/mappings/CciNistMappingItem.js.map +1 -1
  196. package/lib/src/mappings/CheckovToCciAndNistMappingData.d.ts +5 -0
  197. package/lib/src/mappings/CheckovToCciAndNistMappingData.d.ts.map +1 -0
  198. package/lib/src/mappings/CheckovToCciAndNistMappingData.js +2695 -0
  199. package/lib/src/mappings/CheckovToCciAndNistMappingData.js.map +1 -0
  200. package/lib/src/mappings/CweNistMapping.d.ts +1 -0
  201. package/lib/src/mappings/CweNistMapping.d.ts.map +1 -0
  202. package/lib/src/mappings/CweNistMapping.js +1 -0
  203. package/lib/src/mappings/CweNistMapping.js.map +1 -1
  204. package/lib/src/mappings/CweNistMappingData.d.ts +1 -0
  205. package/lib/src/mappings/CweNistMappingData.d.ts.map +1 -0
  206. package/lib/src/mappings/CweNistMappingData.js.map +1 -1
  207. package/lib/src/mappings/CweNistMappingItem.d.ts +1 -0
  208. package/lib/src/mappings/CweNistMappingItem.d.ts.map +1 -0
  209. package/lib/src/mappings/CweNistMappingItem.js +5 -0
  210. package/lib/src/mappings/CweNistMappingItem.js.map +1 -1
  211. package/lib/src/mappings/NessusPluginNistMappingData.d.ts +1 -0
  212. package/lib/src/mappings/NessusPluginNistMappingData.d.ts.map +1 -0
  213. package/lib/src/mappings/NessusPluginNistMappingData.js.map +1 -1
  214. package/lib/src/mappings/NessusPluginsNistMapping.d.ts +1 -0
  215. package/lib/src/mappings/NessusPluginsNistMapping.d.ts.map +1 -0
  216. package/lib/src/mappings/NessusPluginsNistMapping.js +1 -0
  217. package/lib/src/mappings/NessusPluginsNistMapping.js.map +1 -1
  218. package/lib/src/mappings/NessusPluginsNistMappingItem.d.ts +1 -0
  219. package/lib/src/mappings/NessusPluginsNistMappingItem.d.ts.map +1 -0
  220. package/lib/src/mappings/NessusPluginsNistMappingItem.js +4 -0
  221. package/lib/src/mappings/NessusPluginsNistMappingItem.js.map +1 -1
  222. package/lib/src/mappings/NiktoNistMapping.d.ts +1 -0
  223. package/lib/src/mappings/NiktoNistMapping.d.ts.map +1 -0
  224. package/lib/src/mappings/NiktoNistMapping.js.map +1 -1
  225. package/lib/src/mappings/NiktoNistMappingData.d.ts +1 -0
  226. package/lib/src/mappings/NiktoNistMappingData.d.ts.map +1 -0
  227. package/lib/src/mappings/NiktoNistMappingData.js.map +1 -1
  228. package/lib/src/mappings/NiktoNistMappingItem.d.ts +1 -0
  229. package/lib/src/mappings/NiktoNistMappingItem.d.ts.map +1 -0
  230. package/lib/src/mappings/NiktoNistMappingItem.js +4 -0
  231. package/lib/src/mappings/NiktoNistMappingItem.js.map +1 -1
  232. package/lib/src/mappings/NistCciMappingData.d.ts +1 -0
  233. package/lib/src/mappings/NistCciMappingData.d.ts.map +1 -0
  234. package/lib/src/mappings/NistCciMappingData.js.map +1 -1
  235. package/lib/src/mappings/OwaspNistMapping.d.ts +1 -0
  236. package/lib/src/mappings/OwaspNistMapping.d.ts.map +1 -0
  237. package/lib/src/mappings/OwaspNistMapping.js +18 -7
  238. package/lib/src/mappings/OwaspNistMapping.js.map +1 -1
  239. package/lib/src/mappings/OwaspNistMappingData.d.ts +1 -0
  240. package/lib/src/mappings/OwaspNistMappingData.d.ts.map +1 -0
  241. package/lib/src/mappings/OwaspNistMappingData.js.map +1 -1
  242. package/lib/src/mappings/OwaspNistMappingItem.d.ts +1 -0
  243. package/lib/src/mappings/OwaspNistMappingItem.d.ts.map +1 -0
  244. package/lib/src/mappings/OwaspNistMappingItem.js +5 -0
  245. package/lib/src/mappings/OwaspNistMappingItem.js.map +1 -1
  246. package/lib/src/mappings/ScoutsuiteNistMapping.d.ts +1 -0
  247. package/lib/src/mappings/ScoutsuiteNistMapping.d.ts.map +1 -0
  248. package/lib/src/mappings/ScoutsuiteNistMapping.js +1 -0
  249. package/lib/src/mappings/ScoutsuiteNistMapping.js.map +1 -1
  250. package/lib/src/mappings/ScoutsuiteNistMappingData.d.ts +1 -0
  251. package/lib/src/mappings/ScoutsuiteNistMappingData.d.ts.map +1 -0
  252. package/lib/src/mappings/ScoutsuiteNistMappingData.js.map +1 -1
  253. package/lib/src/mappings/ScoutsuiteNistMappingItem.d.ts +1 -0
  254. package/lib/src/mappings/ScoutsuiteNistMappingItem.d.ts.map +1 -0
  255. package/lib/src/mappings/ScoutsuiteNistMappingItem.js +2 -0
  256. package/lib/src/mappings/ScoutsuiteNistMappingItem.js.map +1 -1
  257. package/lib/src/msft-secure-score-mapper.d.ts +1 -0
  258. package/lib/src/msft-secure-score-mapper.d.ts.map +1 -0
  259. package/lib/src/msft-secure-score-mapper.js +202 -185
  260. package/lib/src/msft-secure-score-mapper.js.map +1 -1
  261. package/lib/src/nessus-mapper.d.ts +2 -1
  262. package/lib/src/nessus-mapper.d.ts.map +1 -0
  263. package/lib/src/nessus-mapper.js +122 -105
  264. package/lib/src/nessus-mapper.js.map +1 -1
  265. package/lib/src/netsparker-mapper.d.ts +7 -0
  266. package/lib/src/netsparker-mapper.d.ts.map +1 -0
  267. package/lib/src/netsparker-mapper.js +34 -9
  268. package/lib/src/netsparker-mapper.js.map +1 -1
  269. package/lib/src/neuvector-mapper.d.ts +1 -0
  270. package/lib/src/neuvector-mapper.d.ts.map +1 -0
  271. package/lib/src/neuvector-mapper.js +120 -117
  272. package/lib/src/neuvector-mapper.js.map +1 -1
  273. package/lib/src/nikto-mapper.d.ts +1 -0
  274. package/lib/src/nikto-mapper.d.ts.map +1 -0
  275. package/lib/src/nikto-mapper.js +85 -74
  276. package/lib/src/nikto-mapper.js.map +1 -1
  277. package/lib/src/prisma-mapper.d.ts +1 -0
  278. package/lib/src/prisma-mapper.d.ts.map +1 -0
  279. package/lib/src/prisma-mapper.js +138 -128
  280. package/lib/src/prisma-mapper.js.map +1 -1
  281. package/lib/src/sarif-mapper.d.ts +1 -0
  282. package/lib/src/sarif-mapper.d.ts.map +1 -0
  283. package/lib/src/sarif-mapper.js +116 -105
  284. package/lib/src/sarif-mapper.js.map +1 -1
  285. package/lib/src/scoutsuite-mapper.d.ts +1 -0
  286. package/lib/src/scoutsuite-mapper.d.ts.map +1 -0
  287. package/lib/src/scoutsuite-mapper.js +174 -163
  288. package/lib/src/scoutsuite-mapper.js.map +1 -1
  289. package/lib/src/snyk-mapper.d.ts +1 -0
  290. package/lib/src/snyk-mapper.d.ts.map +1 -0
  291. package/lib/src/snyk-mapper.js +112 -100
  292. package/lib/src/snyk-mapper.js.map +1 -1
  293. package/lib/src/sonarqube-mapper.d.ts +18 -5
  294. package/lib/src/sonarqube-mapper.d.ts.map +1 -0
  295. package/lib/src/sonarqube-mapper.js +525 -271
  296. package/lib/src/sonarqube-mapper.js.map +1 -1
  297. package/lib/src/splunk-mapper.d.ts +3 -2
  298. package/lib/src/splunk-mapper.d.ts.map +1 -0
  299. package/lib/src/splunk-mapper.js +69 -12
  300. package/lib/src/splunk-mapper.js.map +1 -1
  301. package/lib/src/trufflehog-mapper.d.ts +1 -0
  302. package/lib/src/trufflehog-mapper.d.ts.map +1 -0
  303. package/lib/src/trufflehog-mapper.js +72 -69
  304. package/lib/src/trufflehog-mapper.js.map +1 -1
  305. package/lib/src/twistlock-mapper.d.ts +1 -0
  306. package/lib/src/twistlock-mapper.d.ts.map +1 -0
  307. package/lib/src/twistlock-mapper.js +140 -126
  308. package/lib/src/twistlock-mapper.js.map +1 -1
  309. package/lib/src/utils/CCI_List.d.ts +1 -0
  310. package/lib/src/utils/CCI_List.d.ts.map +1 -0
  311. package/lib/src/utils/CCI_List.js.map +1 -1
  312. package/lib/src/utils/attestations.d.ts +1 -0
  313. package/lib/src/utils/attestations.d.ts.map +1 -0
  314. package/lib/src/utils/attestations.js +28 -13
  315. package/lib/src/utils/attestations.js.map +1 -1
  316. package/lib/src/utils/compliance.d.ts +1 -0
  317. package/lib/src/utils/compliance.d.ts.map +1 -0
  318. package/lib/src/utils/compliance.js +11 -3
  319. package/lib/src/utils/compliance.js.map +1 -1
  320. package/lib/src/utils/fingerprinting.d.ts +2 -0
  321. package/lib/src/utils/fingerprinting.d.ts.map +1 -0
  322. package/lib/src/utils/fingerprinting.js +28 -11
  323. package/lib/src/utils/fingerprinting.js.map +1 -1
  324. package/lib/src/utils/global.d.ts +3 -1
  325. package/lib/src/utils/global.d.ts.map +1 -0
  326. package/lib/src/utils/global.js +34 -15
  327. package/lib/src/utils/global.js.map +1 -1
  328. package/lib/src/utils/parseJson.d.ts +1 -0
  329. package/lib/src/utils/parseJson.d.ts.map +1 -0
  330. package/lib/src/utils/parseJson.js +7 -3
  331. package/lib/src/utils/parseJson.js.map +1 -1
  332. package/lib/src/utils/result.d.ts +1 -0
  333. package/lib/src/utils/result.d.ts.map +1 -0
  334. package/lib/src/utils/result.js.map +1 -1
  335. package/lib/src/utils/splunk-tools.d.ts +2 -1
  336. package/lib/src/utils/splunk-tools.d.ts.map +1 -0
  337. package/lib/src/utils/splunk-tools.js +52 -31
  338. package/lib/src/utils/splunk-tools.js.map +1 -1
  339. package/lib/src/veracode-mapper.d.ts +1 -0
  340. package/lib/src/veracode-mapper.d.ts.map +1 -0
  341. package/lib/src/veracode-mapper.js +50 -7
  342. package/lib/src/veracode-mapper.js.map +1 -1
  343. package/lib/src/xccdf-results-mapper.d.ts +7 -0
  344. package/lib/src/xccdf-results-mapper.d.ts.map +1 -0
  345. package/lib/src/xccdf-results-mapper.js +336 -301
  346. package/lib/src/xccdf-results-mapper.js.map +1 -1
  347. package/lib/src/zap-mapper.d.ts +8 -0
  348. package/lib/src/zap-mapper.d.ts.map +1 -0
  349. package/lib/src/zap-mapper.js +119 -90
  350. package/lib/src/zap-mapper.js.map +1 -1
  351. package/lib/tsconfig.build.tsbuildinfo +1 -0
  352. package/lib/types/neuvector-types.d.ts +1 -0
  353. package/lib/types/neuvector-types.d.ts.map +1 -0
  354. package/lib/types/neuvector-types.js +80 -0
  355. package/lib/types/neuvector-types.js.map +1 -1
  356. package/lib/types/splunk-config-types.d.ts +1 -0
  357. package/lib/types/splunk-config-types.d.ts.map +1 -0
  358. package/lib/types/splunk-config-types.js.map +1 -1
  359. package/lib/types/splunk-control-types.d.ts +1 -0
  360. package/lib/types/splunk-control-types.d.ts.map +1 -0
  361. package/lib/types/splunk-control-types.js.map +1 -1
  362. package/lib/types/splunk-profile-types.d.ts +1 -0
  363. package/lib/types/splunk-profile-types.d.ts.map +1 -0
  364. package/lib/types/splunk-profile-types.js.map +1 -1
  365. package/lib/types/splunk-report-types.d.ts +1 -0
  366. package/lib/types/splunk-report-types.d.ts.map +1 -0
  367. package/lib/types/splunk-report-types.js.map +1 -1
  368. package/package.json +19 -40
  369. package/lib/data/converters/csv2json.ts +0 -36
  370. package/lib/data/converters/xml2json.ts +0 -57
@@ -15,19 +15,30 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
39
  exports.SonarqubeResults = exports.SonarqubeMapper = void 0;
30
40
  const axios_1 = __importDefault(require("axios"));
41
+ const rax = __importStar(require("retry-axios"));
31
42
  const _ = __importStar(require("lodash"));
32
43
  const semver_1 = require("semver");
33
44
  const inspecjs_1 = require("inspecjs");
@@ -38,6 +49,7 @@ const CweNistMapping_1 = require("./mappings/CweNistMapping");
38
49
  const OwaspNistMapping_1 = require("./mappings/OwaspNistMapping");
39
50
  const global_1 = require("./utils/global");
40
51
  const logger = (0, global_1.createWinstonLogger)('SonarQube2HDF');
52
+ // the Sonarqube schema typings are meant to support the four versions out right now (8, 9, 10, and 2025/25). 9 and 25 are supposed to be LTS releases. 8 is currently used by the Sonarcloud deployment though Sonarqube POCs say that it is no longer supported / they do not see many deployments of it.
41
53
  var SonarqubeVersion;
42
54
  (function (SonarqubeVersion) {
43
55
  SonarqubeVersion["Eight"] = "8.0.0";
@@ -45,6 +57,7 @@ var SonarqubeVersion;
45
57
  SonarqubeVersion["Ten"] = "10.0.0";
46
58
  SonarqubeVersion["Twenty_five"] = "2025.0.0";
47
59
  })(SonarqubeVersion || (SonarqubeVersion = {}));
60
+ // intentionally open ended to support versions less than 8, but it is unlikely that they will be out there based on discussions with Sonar engineers
48
61
  function isSonarqubeVersionEight(version) {
49
62
  const nextHigherVersion = SonarqubeVersion.Nine;
50
63
  const v = (0, semver_1.coerce)(version);
@@ -70,13 +83,25 @@ function isSonarqubeVersionTen(version) {
70
83
  return (0, semver_1.lt)(v, nextHigherVersion);
71
84
  }
72
85
  function isSonarqubeVersionTwenty_five(version) {
73
- const nextHigherVersion = '2026.0.0';
86
+ const nextHigherVersion = '2026.0.0'; // using 26 for now, but I am unsure what the actual next major version will be - this function can be changed once we identify the next version that contains impactful breaking changes
74
87
  const v = (0, semver_1.coerce)(version);
75
88
  if (v === null) {
76
89
  throw new Error(`Was not able to coerce ${version} into a semver compatible version string`);
77
90
  }
78
91
  return (0, semver_1.lt)(v, nextHigherVersion);
79
92
  }
93
+ function isBeforeSonarqubeVersion(version, comparisonVersion) {
94
+ const v = (0, semver_1.coerce)(version);
95
+ if (v === null) {
96
+ throw new Error(`Was not able to coerce ${version} into a semver compatible version string`);
97
+ }
98
+ const cv = (0, semver_1.coerce)(comparisonVersion);
99
+ if (cv === null) {
100
+ throw new Error(`Was not able to coerce ${comparisonVersion} into a semver compatible version string`);
101
+ }
102
+ return (0, semver_1.lt)(v, cv);
103
+ }
104
+ // https://docs.sonarsource.com/sonarqube-server/latest/user-guide/rules/overview/#how-severities-are-assigned
80
105
  const IMPACT_MAPPING = new Map([
81
106
  ['blocker', 1.0],
82
107
  ['critical', 0.7],
@@ -89,7 +114,7 @@ const OWASP_NIST_MAPPING = new OwaspNistMapping_1.OwaspNistMapping();
89
114
  function parseOwaspInSysTags(issue) {
90
115
  return issue.ruleInformation.rule.sysTags
91
116
  .filter((s) => s.toLowerCase().startsWith('owasp-'))
92
- .map((t) => t.substring('owasp-'.length).toUpperCase());
117
+ .map((t) => t.substring('owasp-'.length).toUpperCase()); // this will just look like 'A3'
93
118
  }
94
119
  function parseOwaspTags(issue) {
95
120
  let searchSpace = '';
@@ -102,7 +127,7 @@ function parseOwaspTags(issue) {
102
127
  }
103
128
  const searchSpaceMatches = [
104
129
  ...searchSpace.matchAll(/> ?OWASP.*?(Top .*?A\d\d?)/gu)
105
- ].map((m) => m[1]);
130
+ ].map((m) => m[1]); // get the capture group which looks like 'Top 10 2021 Category A1'
106
131
  const sysTagMatches = parseOwaspInSysTags(issue);
107
132
  const totalMatches = searchSpaceMatches.concat(sysTagMatches);
108
133
  if (totalMatches.length) {
@@ -119,7 +144,7 @@ function parseCweTags(issue) {
119
144
  if (rule.descriptionSections) {
120
145
  searchSpace += rule.descriptionSections.map((s) => s.content).join('');
121
146
  }
122
- const uniqueCwes = _.uniq(searchSpace.match(/CWE-\d\d\d?\d?\d?\d?\d/gi));
147
+ const uniqueCwes = _.uniq(searchSpace.match(/CWE-\d\d\d?\d?\d?\d?\d/gi)); // CWE IDs are embedded inside of the HTML
123
148
  if (uniqueCwes.length) {
124
149
  return uniqueCwes;
125
150
  }
@@ -128,255 +153,276 @@ function parseCweTags(issue) {
128
153
  function parseNistTags(issue) {
129
154
  const uniqueNist = _.uniq((parseCweTags(issue) ?? [])
130
155
  .flatMap((t) => CWE_NIST_MAPPING.nistFilter(t.split('-')[1]))
131
- .concat((parseOwaspInSysTags(issue) ?? []).flatMap((t) => OWASP_NIST_MAPPING.nistFilterNoDefault(t))));
156
+ .concat(
157
+ // adding in the systags' owasp tag since in older sonarqube versions sometimes no other guidance alignment is provided
158
+ (parseOwaspInSysTags(issue) ?? []).flatMap((t) => OWASP_NIST_MAPPING.nistFilterNoDefault(t))));
132
159
  if (uniqueNist.length) {
133
160
  return uniqueNist;
134
161
  }
135
- return ['SA-11'];
162
+ return ['SA-11']; // Sonarqube is a static code analysis tool so we'll use SA-11 (DEVELOPER SECURITY TESTING AND EVALUATION) to handle all the bugs and code smells as a default for whenever it doesn't have security guidance to give us. Explicitly not using RA-5 (VULNERABILITY SCANNING) since all of those seem to have guidance associated with them.
136
163
  }
137
164
  class SonarqubeMapper extends base_converter_1.BaseConverter {
138
- constructor(data, withRaw = false) {
139
- super(data);
140
- this.data = data;
141
- this.mappings = {
142
- platform: {
143
- name: 'Heimdall Tools',
144
- release: package_json_1.version
145
- },
146
- version: package_json_1.version,
147
- statistics: {},
148
- profiles: [
149
- {
150
- name: 'SonarQube Scan',
151
- version: {
152
- transformer: (data) => `SonarQube v${data.sonarqubeVersion}`
153
- },
154
- title: {
155
- transformer: (data) => {
156
- const branch = data.branchName ? ` branch ${data.branchName}` : '';
157
- const pullrequest = data.pullRequestID
158
- ? ` pull request ${data.pullRequestID}`
159
- : '';
160
- const org = data.organization
161
- ? ` organization ${data.organization}`
162
- : '';
163
- return `SonarQube Scan of project ${data.projectKey} on ${data.sonarqubeHost} at ${new Date().toISOString()}${data.branchName || data.pullRequestID || data.organization ? ' using' : ''}${[branch, pullrequest, org].filter((s) => s).join(',')}`;
164
- }
165
- },
166
- supports: [],
167
- attributes: [],
168
- groups: [],
169
- status: 'loaded',
170
- controls: [
171
- {
172
- path: 'search.issues',
173
- key: 'id',
174
- desc: {
175
- transformer: (issue) => {
176
- const rule = issue.ruleInformation.rule;
177
- if ('htmlDesc' in rule) {
178
- return rule.htmlDesc;
179
- }
180
- if (!rule.descriptionSections) {
181
- return '';
182
- }
183
- const def = rule.descriptionSections.find((d) => d.key === 'default');
184
- if (def) {
185
- return def.content;
186
- }
187
- const introduction = rule.descriptionSections.find((d) => d.key === 'introduction');
188
- const rootcause = rule.descriptionSections.find((d) => d.key === 'root_cause');
189
- return [introduction, rootcause]
190
- .filter((s) => s !== undefined)
191
- .map((s) => s.content)
192
- .join('\n');
165
+ data;
166
+ withRaw;
167
+ mappings = {
168
+ platform: {
169
+ name: 'Heimdall Tools',
170
+ release: package_json_1.version
171
+ },
172
+ version: package_json_1.version,
173
+ statistics: {},
174
+ profiles: [
175
+ {
176
+ name: 'SonarQube Scan',
177
+ version: {
178
+ transformer: (data) => `SonarQube v${data.sonarqubeVersion}`
179
+ },
180
+ title: {
181
+ transformer: (data) => {
182
+ const branch = data.branchName ? ` branch ${data.branchName}` : '';
183
+ const pullrequest = data.pullRequestID
184
+ ? ` pull request ${data.pullRequestID}`
185
+ : '';
186
+ const org = data.organization
187
+ ? ` organization ${data.organization}`
188
+ : '';
189
+ return `SonarQube Scan of project ${data.projectKey} on ${data.sonarqubeHost} at ${new Date().toISOString()}${data.branchName || data.pullRequestID || data.organization ? ' using' : ''}${[branch, pullrequest, org].filter((s) => s).join(',')}`;
190
+ }
191
+ },
192
+ supports: [],
193
+ attributes: [],
194
+ groups: [],
195
+ status: 'loaded',
196
+ controls: [
197
+ {
198
+ path: 'search.issues',
199
+ key: 'id',
200
+ desc: {
201
+ transformer: (issue) => {
202
+ const rule = issue.ruleInformation.rule;
203
+ if ('htmlDesc' in rule) {
204
+ return rule.htmlDesc;
193
205
  }
206
+ if (!rule.descriptionSections) {
207
+ return '';
208
+ }
209
+ const def = rule.descriptionSections.find((d) => d.key === 'default');
210
+ if (def) {
211
+ return def.content;
212
+ }
213
+ const introduction = rule.descriptionSections.find((d) => d.key === 'introduction');
214
+ const rootcause = rule.descriptionSections.find((d) => d.key === 'root_cause');
215
+ return [introduction, rootcause]
216
+ .filter((s) => s !== undefined)
217
+ .map((s) => s.content)
218
+ .join('\n');
219
+ }
220
+ },
221
+ refs: [],
222
+ source_location: {},
223
+ id: { path: 'rule' },
224
+ title: { path: 'ruleInformation.rule.name' },
225
+ impact: {
226
+ path: 'severity',
227
+ transformer: (0, base_converter_1.impactMapping)(IMPACT_MAPPING)
228
+ },
229
+ tags: {
230
+ cci: {
231
+ transformer: (issue) => (0, global_1.getCCIsForNISTTags)(parseNistTags(issue) ?? [])
194
232
  },
195
- refs: [],
196
- source_location: {},
197
- id: { path: 'rule' },
198
- title: { path: 'ruleInformation.rule.name' },
199
- impact: {
200
- path: 'severity',
201
- transformer: (0, base_converter_1.impactMapping)(IMPACT_MAPPING)
202
- },
203
- tags: {
204
- cci: {
205
- transformer: (issue) => (0, global_1.getCCIsForNISTTags)(parseNistTags(issue) ?? [])
206
- },
207
- nist: { transformer: parseNistTags },
208
- cweid: { transformer: parseCweTags },
209
- owasp: { transformer: parseOwaspTags },
210
- createdAt: { path: 'ruleInformation.rule.createdAt' },
211
- debtRemFnType: { path: 'ruleInformation.rule.debtRemFnType' },
212
- defaultDebtRemFnType: {
213
- path: 'ruleInformation.rule.defaultDebtRemFnType'
214
- },
215
- isExternal: { path: 'ruleInformation.rule.isExternal' },
216
- isTemplate: { path: 'ruleInformation.rule.isTemplate' },
217
- langName: { path: 'ruleInformation.rule.langName' },
218
- remFnBaseEffort: { path: 'ruleInformation.rule.remFnBaseEffort' },
219
- remFnOverloaded: { path: 'ruleInformation.rule.remFnOverloaded' },
220
- remFnType: { path: 'ruleInformation.rule.remFnType' },
221
- repo: { path: 'ruleInformation.rule.repo' },
222
- scope: { path: 'ruleInformation.rule.scope' },
223
- ruleSeverity: { path: 'ruleInformation.rule.severity' },
224
- status: { path: 'ruleInformation.rule.status' },
225
- transformer: (issue) => ({
226
- ...(0, global_1.conditionallyProvideAttribute)('Actives', issue.ruleInformation.actives, issue.ruleInformation.actives.length !== 0),
227
- ...(0, global_1.conditionallyProvideAttribute)('Clean Code Attribute', issue.ruleInformation.rule.cleanCodeAttribute, issue.ruleInformation.rule.cleanCodeAttribute?.length !== 0),
228
- ...(0, global_1.conditionallyProvideAttribute)('Clean Code Attribute Category', issue.ruleInformation.rule.cleanCodeAttributeCategory, issue.ruleInformation.rule.cleanCodeAttributeCategory
229
- ?.length !== 0),
230
- ...(0, global_1.conditionallyProvideAttribute)('Debt Overloaded', 'debtOverloaded' in issue.ruleInformation.rule &&
231
- issue.ruleInformation.rule.debtOverloaded, 'debtOverloaded' in issue.ruleInformation.rule &&
232
- issue.ruleInformation.rule.debtOverloaded !== undefined),
233
- ...(0, global_1.conditionallyProvideAttribute)('Debt Rem Fn Coeff', 'debtRemFnCoeff' in issue.ruleInformation.rule &&
234
- issue.ruleInformation.rule.debtRemFnCoeff, 'debtRemFnCoeff' in issue.ruleInformation.rule &&
235
- issue.ruleInformation.rule.debtRemFnCoeff !== undefined),
236
- ...(0, global_1.conditionallyProvideAttribute)('Debt Rem Fn Offset', 'debtRemFnOffset' in issue.ruleInformation.rule &&
237
- issue.ruleInformation.rule.debtRemFnOffset, 'debtRemFnOffset' in issue.ruleInformation.rule),
238
- ...(0, global_1.conditionallyProvideAttribute)('Default Debt Rem Fn Coeff', 'defaultDebtRemFnCoeff' in issue.ruleInformation.rule &&
239
- issue.ruleInformation.rule.defaultDebtRemFnCoeff, 'defaultDebtRemFnCoeff' in issue.ruleInformation.rule &&
240
- issue.ruleInformation.rule.defaultDebtRemFnCoeff !==
241
- undefined),
242
- ...(0, global_1.conditionallyProvideAttribute)('Default Debt Rem Fn Offset', 'defaultDebtRemFnOffset' in issue.ruleInformation.rule &&
243
- issue.ruleInformation.rule.defaultDebtRemFnOffset, 'defaultDebtRemFnOffset' in issue.ruleInformation.rule),
244
- ...(0, global_1.conditionallyProvideAttribute)('Education Principles', 'educationPrinciples' in issue.ruleInformation.rule &&
245
- issue.ruleInformation.rule.educationPrinciples, 'educationPrinciples' in issue.ruleInformation.rule &&
246
- issue.ruleInformation.rule.educationPrinciples?.length !== 0),
247
- ...(0, global_1.conditionallyProvideAttribute)('Effort To Fix Description', 'effortToFixDescription' in issue.ruleInformation.rule &&
248
- issue.ruleInformation.rule.effortToFixDescription, 'effortToFixDescription' in issue.ruleInformation.rule &&
249
- issue.ruleInformation.rule.effortToFixDescription !==
250
- undefined),
251
- ...(0, global_1.conditionallyProvideAttribute)('Impacts', issue.ruleInformation.rule.impacts, issue.ruleInformation.rule.impacts?.length !== 0),
252
- ...(0, global_1.conditionallyProvideAttribute)('Issue Type Vulnerability', true, issue.type === 'VULNERABILITY'),
253
- ...(0, global_1.conditionallyProvideAttribute)('Issue Type Bug', true, issue.type === 'BUG'),
254
- ...(0, global_1.conditionallyProvideAttribute)('Issue Type Code Smell', true, issue.type === 'CODE_SMELL'),
255
- ...(0, global_1.conditionallyProvideAttribute)('Params', issue.ruleInformation.rule.params, issue.ruleInformation.rule.params?.length !== 0),
256
- ...(0, global_1.conditionallyProvideAttribute)('Security Standards', issue.ruleInformation.rule.securityStandards, issue.ruleInformation.rule.securityStandards?.length !== 0),
257
- ...(0, global_1.conditionallyProvideAttribute)('Sys Tags', issue.ruleInformation.rule.sysTags, issue.ruleInformation.rule.sysTags?.length !== 0),
258
- ...(0, global_1.conditionallyProvideAttribute)('Tags', issue.ruleInformation.rule.tags, issue.ruleInformation.rule.tags?.length !== 0),
259
- ...(0, global_1.conditionallyProvideAttribute)('Updated At', 'updatedAt' in issue.ruleInformation.rule &&
260
- issue.ruleInformation.rule.updatedAt, 'updatedAt' in issue.ruleInformation.rule)
261
- })
233
+ nist: { transformer: parseNistTags },
234
+ cweid: { transformer: parseCweTags },
235
+ owasp: { transformer: parseOwaspTags },
236
+ createdAt: { path: 'ruleInformation.rule.createdAt' },
237
+ debtRemFnType: { path: 'ruleInformation.rule.debtRemFnType' },
238
+ defaultDebtRemFnType: {
239
+ path: 'ruleInformation.rule.defaultDebtRemFnType'
262
240
  },
263
- results: [
264
- {
265
- status: inspecjs_1.ExecJSON.ControlResultStatus.Failed,
266
- code_desc: { path: 'codeSnippet' },
267
- start_time: { path: 'creationDate' },
268
- message: {
269
- transformer: (issue) => JSON.stringify({
270
- Message: issue.message,
271
- Author: issue.author,
272
- 'Creation Date': issue.creationDate,
273
- Debt: issue.debt,
274
- Effort: issue.effort,
275
- ...(0, global_1.conditionallyProvideAttribute)('Issue Status', issue.issueStatus, issue.issueStatus?.length !== 0),
276
- ...(0, global_1.conditionallyProvideAttribute)('Resolution', issue.resolution, issue.resolution?.length !== 0),
277
- Status: issue.status,
278
- 'Update Date': issue.updateDate,
279
- ...(0, global_1.conditionallyProvideAttribute)('Actions', issue.actions, issue.actions?.length !== 0),
280
- ...(0, global_1.conditionallyProvideAttribute)('Attr', issue.attr, issue.attr !== undefined),
281
- ...(0, global_1.conditionallyProvideAttribute)('Code Variants', 'codeVariants' in issue && issue.codeVariants, 'codeVariants' in issue &&
282
- issue.codeVariants?.length !== 0),
283
- ...(0, global_1.conditionallyProvideAttribute)('Comments', issue.comments, issue.comments?.length !== 0),
284
- ...(0, global_1.conditionallyProvideAttribute)('Flows', issue.flows, issue.flows?.length !== 0),
285
- ...(0, global_1.conditionallyProvideAttribute)('From Hotspot', 'fromHotspot' in issue && issue.fromHotspot, 'fromHotspot' in issue &&
286
- issue.fromHotspot !== undefined &&
287
- issue.fromHotspot !== null),
288
- Hash: issue.hash,
289
- Key: issue.key,
290
- ...(0, global_1.conditionallyProvideAttribute)('Message Formattings', issue.messageFormattings, issue.messageFormattings?.length !== 0),
291
- ...(0, global_1.conditionallyProvideAttribute)('Prioritized Rule', 'prioritizedRule' in issue && issue.prioritizedRule, 'prioritizedRule' in issue),
292
- ...(0, global_1.conditionallyProvideAttribute)('Project Name', issue.projectName, issue.projectName?.length !== 0),
293
- ...(0, global_1.conditionallyProvideAttribute)('Quick Fix Available', 'quickFixAvailable' in issue &&
294
- issue.quickFixAvailable, 'quickFixAvailable' in issue &&
295
- issue.quickFixAvailable !== undefined),
296
- ...(0, global_1.conditionallyProvideAttribute)('Rule Description Context Key', 'ruleDescriptionContextKey' in issue &&
297
- issue.ruleDescriptionContextKey, 'ruleDescriptionContextKey' in issue &&
298
- issue.ruleDescriptionContextKey?.length !== 0),
299
- ...(0, global_1.conditionallyProvideAttribute)('Tags', issue.tags, issue.tags?.length !== 0),
300
- ...(0, global_1.conditionallyProvideAttribute)('Transitions', issue.transitions, issue.transitions?.length !== 0)
301
- }, null, 2)
302
- }
241
+ isExternal: { path: 'ruleInformation.rule.isExternal' },
242
+ isTemplate: { path: 'ruleInformation.rule.isTemplate' },
243
+ langName: { path: 'ruleInformation.rule.langName' },
244
+ remFnBaseEffort: { path: 'ruleInformation.rule.remFnBaseEffort' },
245
+ remFnOverloaded: { path: 'ruleInformation.rule.remFnOverloaded' },
246
+ remFnType: { path: 'ruleInformation.rule.remFnType' },
247
+ repo: { path: 'ruleInformation.rule.repo' },
248
+ scope: { path: 'ruleInformation.rule.scope' },
249
+ ruleSeverity: { path: 'ruleInformation.rule.severity' },
250
+ status: { path: 'ruleInformation.rule.status' },
251
+ transformer: (issue) => ({
252
+ ...(0, global_1.conditionallyProvideAttribute)('Actives', issue.ruleInformation.actives, issue.ruleInformation.actives.length !== 0),
253
+ ...(0, global_1.conditionallyProvideAttribute)('Clean Code Attribute', issue.ruleInformation.rule.cleanCodeAttribute, issue.ruleInformation.rule.cleanCodeAttribute?.length !== 0),
254
+ ...(0, global_1.conditionallyProvideAttribute)('Clean Code Attribute Category', issue.ruleInformation.rule.cleanCodeAttributeCategory, issue.ruleInformation.rule.cleanCodeAttributeCategory
255
+ ?.length !== 0),
256
+ ...(0, global_1.conditionallyProvideAttribute)('Debt Overloaded', 'debtOverloaded' in issue.ruleInformation.rule &&
257
+ issue.ruleInformation.rule.debtOverloaded, 'debtOverloaded' in issue.ruleInformation.rule &&
258
+ issue.ruleInformation.rule.debtOverloaded !== undefined),
259
+ ...(0, global_1.conditionallyProvideAttribute)('Debt Rem Fn Coeff', 'debtRemFnCoeff' in issue.ruleInformation.rule &&
260
+ issue.ruleInformation.rule.debtRemFnCoeff, 'debtRemFnCoeff' in issue.ruleInformation.rule &&
261
+ issue.ruleInformation.rule.debtRemFnCoeff !== undefined),
262
+ ...(0, global_1.conditionallyProvideAttribute)('Debt Rem Fn Offset', 'debtRemFnOffset' in issue.ruleInformation.rule &&
263
+ issue.ruleInformation.rule.debtRemFnOffset, 'debtRemFnOffset' in issue.ruleInformation.rule),
264
+ ...(0, global_1.conditionallyProvideAttribute)('Default Debt Rem Fn Coeff', 'defaultDebtRemFnCoeff' in issue.ruleInformation.rule &&
265
+ issue.ruleInformation.rule.defaultDebtRemFnCoeff, 'defaultDebtRemFnCoeff' in issue.ruleInformation.rule &&
266
+ issue.ruleInformation.rule.defaultDebtRemFnCoeff !==
267
+ undefined),
268
+ ...(0, global_1.conditionallyProvideAttribute)('Default Debt Rem Fn Offset', 'defaultDebtRemFnOffset' in issue.ruleInformation.rule &&
269
+ issue.ruleInformation.rule.defaultDebtRemFnOffset, 'defaultDebtRemFnOffset' in issue.ruleInformation.rule),
270
+ ...(0, global_1.conditionallyProvideAttribute)('Education Principles', 'educationPrinciples' in issue.ruleInformation.rule &&
271
+ issue.ruleInformation.rule.educationPrinciples, 'educationPrinciples' in issue.ruleInformation.rule &&
272
+ issue.ruleInformation.rule.educationPrinciples?.length !== 0),
273
+ ...(0, global_1.conditionallyProvideAttribute)('Effort To Fix Description', 'effortToFixDescription' in issue.ruleInformation.rule &&
274
+ issue.ruleInformation.rule.effortToFixDescription, 'effortToFixDescription' in issue.ruleInformation.rule &&
275
+ issue.ruleInformation.rule.effortToFixDescription !==
276
+ undefined),
277
+ ...(0, global_1.conditionallyProvideAttribute)('Impacts', issue.ruleInformation.rule.impacts, issue.ruleInformation.rule.impacts?.length !== 0),
278
+ ...(0, global_1.conditionallyProvideAttribute)('Issue Type Vulnerability', true, issue.type === 'VULNERABILITY'),
279
+ ...(0, global_1.conditionallyProvideAttribute)('Issue Type Bug', true, issue.type === 'BUG'),
280
+ ...(0, global_1.conditionallyProvideAttribute)('Issue Type Code Smell', true, issue.type === 'CODE_SMELL'),
281
+ ...(0, global_1.conditionallyProvideAttribute)('Params', issue.ruleInformation.rule.params, issue.ruleInformation.rule.params?.length !== 0),
282
+ ...(0, global_1.conditionallyProvideAttribute)('Security Standards', issue.ruleInformation.rule.securityStandards, issue.ruleInformation.rule.securityStandards?.length !== 0),
283
+ ...(0, global_1.conditionallyProvideAttribute)('Sys Tags', issue.ruleInformation.rule.sysTags, issue.ruleInformation.rule.sysTags?.length !== 0),
284
+ ...(0, global_1.conditionallyProvideAttribute)('Tags', issue.ruleInformation.rule.tags, issue.ruleInformation.rule.tags?.length !== 0),
285
+ ...(0, global_1.conditionallyProvideAttribute)('Updated At', 'updatedAt' in issue.ruleInformation.rule &&
286
+ issue.ruleInformation.rule.updatedAt, 'updatedAt' in issue.ruleInformation.rule)
287
+ })
288
+ },
289
+ results: [
290
+ {
291
+ status: inspecjs_1.ExecJSON.ControlResultStatus.Failed,
292
+ code_desc: { path: 'codeSnippet' },
293
+ start_time: { path: 'creationDate' },
294
+ message: {
295
+ transformer: (issue) => JSON.stringify({
296
+ // Explanation of the violation
297
+ Message: issue.message,
298
+ // Useful information
299
+ Author: issue.author,
300
+ 'Creation Date': issue.creationDate,
301
+ Debt: issue.debt,
302
+ Effort: issue.effort,
303
+ ...(0, global_1.conditionallyProvideAttribute)('Issue Status', issue.issueStatus, issue.issueStatus?.length !== 0),
304
+ ...(0, global_1.conditionallyProvideAttribute)('Resolution', issue.resolution, issue.resolution?.length !== 0),
305
+ Status: issue.status,
306
+ 'Update Date': issue.updateDate,
307
+ // all the rest
308
+ ...(0, global_1.conditionallyProvideAttribute)('Actions', issue.actions, issue.actions?.length !== 0),
309
+ ...(0, global_1.conditionallyProvideAttribute)('Attr', issue.attr, issue.attr !== undefined),
310
+ ...(0, global_1.conditionallyProvideAttribute)('Code Variants', 'codeVariants' in issue && issue.codeVariants, 'codeVariants' in issue &&
311
+ issue.codeVariants?.length !== 0),
312
+ ...(0, global_1.conditionallyProvideAttribute)('Comments', issue.comments, issue.comments?.length !== 0),
313
+ ...(0, global_1.conditionallyProvideAttribute)('Flows', issue.flows, issue.flows?.length !== 0),
314
+ ...(0, global_1.conditionallyProvideAttribute)('From Hotspot', 'fromHotspot' in issue && issue.fromHotspot, 'fromHotspot' in issue &&
315
+ issue.fromHotspot !== undefined &&
316
+ issue.fromHotspot !== null),
317
+ Hash: issue.hash,
318
+ Key: issue.key,
319
+ ...(0, global_1.conditionallyProvideAttribute)('Message Formattings', issue.messageFormattings, issue.messageFormattings?.length !== 0),
320
+ ...(0, global_1.conditionallyProvideAttribute)('Prioritized Rule', 'prioritizedRule' in issue && issue.prioritizedRule, 'prioritizedRule' in issue),
321
+ ...(0, global_1.conditionallyProvideAttribute)('Project Name', issue.projectName, issue.projectName?.length !== 0),
322
+ ...(0, global_1.conditionallyProvideAttribute)('Quick Fix Available', 'quickFixAvailable' in issue &&
323
+ issue.quickFixAvailable, 'quickFixAvailable' in issue &&
324
+ issue.quickFixAvailable !== undefined),
325
+ ...(0, global_1.conditionallyProvideAttribute)('Rule Description Context Key', 'ruleDescriptionContextKey' in issue &&
326
+ issue.ruleDescriptionContextKey, 'ruleDescriptionContextKey' in issue &&
327
+ issue.ruleDescriptionContextKey?.length !== 0),
328
+ ...(0, global_1.conditionallyProvideAttribute)('Tags', issue.tags, issue.tags?.length !== 0),
329
+ ...(0, global_1.conditionallyProvideAttribute)('Transitions', issue.transitions, issue.transitions?.length !== 0)
330
+ }, null, 2)
303
331
  }
304
- ],
305
- transformer: () => ({
306
- descriptions: {
307
- transformer: (issue) => {
308
- const rule = issue.ruleInformation.rule;
309
- if (rule.descriptionSections &&
310
- rule.descriptionSections.length > 0) {
311
- const def = rule.descriptionSections.find((d) => d.key === 'default');
312
- const introduction = rule.descriptionSections.find((d) => d.key === 'introduction');
313
- const rootcause = rule.descriptionSections.find((d) => d.key === 'root_cause');
314
- const check = rule.descriptionSections.find((d) => d.key === 'assess_the_problem');
315
- const fix = rule.descriptionSections.find((d) => d.key === 'how_to_fix');
316
- const remainder = rule.descriptionSections.filter((d) => ![
317
- 'default',
318
- 'introduction',
319
- 'root_cause',
320
- 'assess_the_problem',
321
- 'how_to_fix'
322
- ].includes(d.key));
323
- const sections = [
324
- def,
325
- def ? introduction : undefined,
326
- def ? rootcause : undefined,
327
- check,
328
- fix,
329
- ...remainder
330
- ]
331
- .filter((s) => s !== undefined)
332
- .map((s) => ({
333
- data: s.content,
334
- label: s.key === 'assess_the_problem'
335
- ? 'check'
336
- : s.key === 'how_to_fix'
337
- ? 'fix'
338
- : s.key
339
- }));
340
- if (sections) {
341
- return sections;
342
- }
332
+ }
333
+ ],
334
+ transformer: () => ({
335
+ descriptions: {
336
+ transformer: (issue) => {
337
+ const rule = issue.ruleInformation.rule;
338
+ if (rule.descriptionSections &&
339
+ rule.descriptionSections.length > 0) {
340
+ const def = rule.descriptionSections.find((d) => d.key === 'default');
341
+ const introduction = rule.descriptionSections.find((d) => d.key === 'introduction');
342
+ const rootcause = rule.descriptionSections.find((d) => d.key === 'root_cause');
343
+ const check = rule.descriptionSections.find((d) => d.key === 'assess_the_problem');
344
+ const fix = rule.descriptionSections.find((d) => d.key === 'how_to_fix');
345
+ const remainder = rule.descriptionSections.filter((d) => ![
346
+ 'default',
347
+ 'introduction',
348
+ 'root_cause',
349
+ 'assess_the_problem',
350
+ 'how_to_fix'
351
+ ].includes(d.key));
352
+ const sections = [
353
+ def,
354
+ def ? introduction : undefined,
355
+ def ? rootcause : undefined,
356
+ check,
357
+ fix,
358
+ ...remainder
359
+ ]
360
+ .filter((s) => s !== undefined)
361
+ .map((s) => ({
362
+ data: s.content,
363
+ label: s.key === 'assess_the_problem'
364
+ ? 'check'
365
+ : s.key === 'how_to_fix'
366
+ ? 'fix'
367
+ : s.key
368
+ }));
369
+ if (sections) {
370
+ return sections;
343
371
  }
344
- return null;
345
372
  }
373
+ return null;
346
374
  }
347
- })
375
+ }
376
+ })
377
+ }
378
+ ],
379
+ sha256: ''
380
+ }
381
+ ],
382
+ passthrough: {
383
+ transformer: (data) => {
384
+ return {
385
+ auxiliary_data: [
386
+ {
387
+ name: 'SonarQube',
388
+ data: {
389
+ ..._.omit(data, 'search.issues')
390
+ }
348
391
  }
349
392
  ],
350
- sha256: ''
351
- }
352
- ],
353
- passthrough: {
354
- transformer: (data) => {
355
- return {
356
- auxiliary_data: [
357
- {
358
- name: 'SonarQube',
359
- data: {
360
- ..._.omit(data, 'search.issues')
361
- }
362
- }
363
- ],
364
- ...(0, global_1.conditionallyProvideAttribute)('raw', data, this.withRaw)
365
- };
366
- }
393
+ ...(0, global_1.conditionallyProvideAttribute)('raw', data, this.withRaw)
394
+ };
367
395
  }
368
- };
396
+ }
397
+ };
398
+ constructor(data, withRaw = false) {
399
+ super(data);
400
+ this.data = data;
369
401
  this.withRaw = withRaw;
370
402
  }
371
403
  }
372
404
  exports.SonarqubeMapper = SonarqubeMapper;
405
+ // Sonarqube used to require using the user token as the username and supplying no password, but added the bearer token method as an option in 10.x. The bearer token method became the only allowed version in 25.x.
373
406
  var AuthenticationMethod;
374
407
  (function (AuthenticationMethod) {
375
408
  AuthenticationMethod[AuthenticationMethod["TokenAsUsername"] = 0] = "TokenAsUsername";
376
409
  AuthenticationMethod[AuthenticationMethod["BearerToken"] = 1] = "BearerToken";
377
410
  })(AuthenticationMethod || (AuthenticationMethod = {}));
378
411
  class SonarqubeResults {
379
- constructor(sonarqubeHost, projectKey, userToken, branchName, pullRequestID, organization, withRaw = false) {
412
+ sonarqubeHost;
413
+ projectKey;
414
+ userToken;
415
+ branchName;
416
+ pullRequestID;
417
+ organization;
418
+ withRaw;
419
+ excludeIssueStatuses;
420
+ authMethod;
421
+ axiosClient;
422
+ constructor(sonarqubeHost, projectKey, userToken, branchName, // if branch/pr are not specified, then sonarqube uses the default branch
423
+ pullRequestID, organization, // sometimes the organization parameter is required for the api/rules/show endpoint - we try to grab it from the issue, but this is here to ensure a fallback if necessary
424
+ withRaw = false, excludeIssueStatuses // user-supplied comma-separated list of additional issue statuses to EXCLUDE from results
425
+ ) {
380
426
  this.sonarqubeHost = sonarqubeHost;
381
427
  this.projectKey = projectKey;
382
428
  this.userToken = userToken;
@@ -384,12 +430,29 @@ class SonarqubeResults {
384
430
  this.pullRequestID = pullRequestID;
385
431
  this.organization = organization;
386
432
  this.withRaw = withRaw;
433
+ this.excludeIssueStatuses = excludeIssueStatuses;
434
+ this.axiosClient = axios_1.default.create();
435
+ const MAX_RETRIES = 5;
436
+ this.axiosClient.defaults.raxConfig = {
437
+ retry: MAX_RETRIES,
438
+ onError: async (e) => {
439
+ const cfg = rax.getConfig(e);
440
+ if (cfg?.currentRetryAttempt !== null &&
441
+ cfg?.currentRetryAttempt !== undefined) {
442
+ logger.debug(`Error occurred: retry attempt #${cfg?.currentRetryAttempt}/${MAX_RETRIES} will happen after backoff`);
443
+ }
444
+ else {
445
+ this.logAxiosError(e);
446
+ }
447
+ }
448
+ };
449
+ rax.attach(this.axiosClient);
387
450
  }
388
451
  logAxiosError(e) {
389
452
  if (e.response) {
390
453
  logger.debug('response');
391
454
  logger.debug(e.response.status);
392
- logger.debug(e.response.data);
455
+ logger.debug((0, util_1.inspect)(e.response.data, { depth: 3 }));
393
456
  }
394
457
  if (e.request) {
395
458
  logger.debug('request');
@@ -400,19 +463,121 @@ class SonarqubeResults {
400
463
  logger.debug('Error', e.message);
401
464
  }
402
465
  }
403
- async getSearchResults() {
404
- let paging = true;
405
- let page = 1;
406
- const results = {
407
- components: [],
408
- effortTotal: 0,
409
- facets: [],
410
- issues: [],
411
- paging: { pageIndex: 0, pageSize: 0, total: 0 }
466
+ // Default statuses to exclude from results (deny-list approach)
467
+ // Pre-10.4 legacy: CLOSED issues are end-of-life (rule deleted/disabled or component removed)
468
+ // 10.4+: FALSE_POSITIVE (user says not real), FIXED (no longer in code, purged after 30 days)
469
+ static DEFAULT_DENY_LIST_LEGACY = ['CLOSED'];
470
+ static DEFAULT_DENY_LIST_MODERN = ['FALSE_POSITIVE', 'FIXED'];
471
+ async discoverIssueStatuses(sonarqubeVersion) {
472
+ const isLegacy = isBeforeSonarqubeVersion(sonarqubeVersion, '10.4.0');
473
+ const statusParamKey = isLegacy ? 'statuses' : 'issueStatuses';
474
+ // Step 1: Discover all valid statuses from the server via /api/webservices/list
475
+ let allStatuses;
476
+ try {
477
+ const response = await this.axiosClient.get(`${this.sonarqubeHost}/api/webservices/list`, {
478
+ ...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
479
+ auth: { username: this.userToken, password: '' }
480
+ }),
481
+ ...(this.authMethod === AuthenticationMethod.BearerToken && {
482
+ headers: { Authorization: `Bearer ${this.userToken}` }
483
+ })
484
+ });
485
+ const issuesService = response.data.webServices?.find((ws) => ws.path === 'api/issues');
486
+ const searchAction = issuesService?.actions?.find((a) => a.key === 'search');
487
+ const statusParam = searchAction?.params?.find((p) => p.key === statusParamKey);
488
+ if (statusParam?.possibleValues?.length) {
489
+ allStatuses = statusParam.possibleValues.map((s) => s.toUpperCase());
490
+ logger.info(`Available issue statuses from server: ${allStatuses.join(',')}`);
491
+ }
492
+ else {
493
+ throw new Error(`Webservices list returned no possibleValues for ${statusParamKey}. ` +
494
+ `Raw param data: ${JSON.stringify(statusParam)}`);
495
+ }
496
+ }
497
+ catch (e) {
498
+ // Step 2: Fallback to hardcoded full status list if discovery fails
499
+ allStatuses = isLegacy
500
+ ? ['OPEN', 'REOPENED', 'CONFIRMED', 'RESOLVED', 'CLOSED']
501
+ : [
502
+ 'OPEN',
503
+ 'CONFIRMED',
504
+ 'FALSE_POSITIVE',
505
+ 'ACCEPTED',
506
+ 'FIXED',
507
+ 'IN_SANDBOX'
508
+ ];
509
+ logger.warn(`Could not discover statuses from server, using fallback: ${allStatuses.join(',')}`);
510
+ logger.debug((0, util_1.inspect)(e, { depth: 3 }));
511
+ }
512
+ // Step 3: Determine which deny-list to use
513
+ const defaultDenyList = isLegacy
514
+ ? SonarqubeResults.DEFAULT_DENY_LIST_LEGACY
515
+ : SonarqubeResults.DEFAULT_DENY_LIST_MODERN;
516
+ let denySet;
517
+ if (this.excludeIssueStatuses) {
518
+ // User-supplied deny-list REPLACES the defaults entirely
519
+ const userExclusions = this.excludeIssueStatuses
520
+ .split(',')
521
+ .map((s) => s.trim().toUpperCase())
522
+ .filter((s) => s.length > 0);
523
+ denySet = new Set(userExclusions);
524
+ // Smart nag: compare user list against defaults
525
+ const defaultSet = new Set(defaultDenyList);
526
+ const sameAsDefault = defaultSet.symmetricDifference(denySet).size === 0;
527
+ if (sameAsDefault) {
528
+ logger.info(`Exclusion list matches the defaults (${[...defaultSet].join(',')}). ` +
529
+ `You can omit --excludeIssueStatuses unless you want to be explicit.`);
530
+ }
531
+ else {
532
+ logger.warn(`Custom status exclusions applied: ${userExclusions.join(',')} ` +
533
+ `(replaces defaults: ${defaultDenyList.join(',')}). ` +
534
+ `If this exclusion should be a default, please consider filing an issue at ` +
535
+ `https://github.com/mitre/heimdall2/issues`);
536
+ }
537
+ }
538
+ else {
539
+ // No user override — use defaults
540
+ denySet = new Set(defaultDenyList);
541
+ logger.info(`Using default status exclusions: ${defaultDenyList.join(',')}`);
542
+ }
543
+ // Step 4: Filter statuses and log the result
544
+ const excluded = allStatuses.filter((s) => denySet.has(s));
545
+ const result = allStatuses.filter((s) => !denySet.has(s));
546
+ if (result.length === 0) {
547
+ logger.warn(`All statuses were excluded by the deny-list. This will likely return no results. ` +
548
+ `Available: ${allStatuses.join(',')} | Excluded: ${excluded.join(',')}`);
549
+ }
550
+ logger.info(`Querying with issue statuses: ${result.join(',')} (excluded: ${excluded.join(',')})`);
551
+ return result.join(',');
552
+ }
553
+ async getSearchResults(sonarqubeVersion) {
554
+ const UPPER_LIMIT = 10000; // there is an upper limit of 10000 search results provided for any given search query (i.e. everything aside from the paging information): https://community.sonarsource.com/t/cannot-get-more-than-10000-results-through-web-api/3662
555
+ const discoveredStatuses = await this.discoverIssueStatuses(sonarqubeVersion);
556
+ const PAGE_SIZE = 100;
557
+ const createSearch = async (component, page, pageSize = PAGE_SIZE) => {
558
+ return this.axiosClient.get(`${this.sonarqubeHost}/api/issues/search`, {
559
+ ...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
560
+ auth: { username: this.userToken, password: '' }
561
+ }),
562
+ ...(this.authMethod === AuthenticationMethod.BearerToken && {
563
+ headers: { Authorization: `Bearer ${this.userToken}` }
564
+ }),
565
+ params: {
566
+ [isBeforeSonarqubeVersion(sonarqubeVersion, '10.2.0')
567
+ ? 'componentKeys'
568
+ : 'components']: component,
569
+ ...(isBeforeSonarqubeVersion(sonarqubeVersion, '10.4.0')
570
+ ? { statuses: discoveredStatuses }
571
+ : { issueStatuses: discoveredStatuses }),
572
+ p: page,
573
+ ps: pageSize,
574
+ ...(this.branchName && { branch: this.branchName }),
575
+ ...(this.pullRequestID && { pullRequest: this.pullRequestID })
576
+ }
577
+ });
412
578
  };
413
- while (paging) {
414
- await axios_1.default
415
- .get(`${this.sonarqubeHost}/api/issues/search`, {
579
+ const createComponentSearch = async (component, page, pageSize = PAGE_SIZE) => {
580
+ return this.axiosClient.get(`${this.sonarqubeHost}/api/components/tree`, {
416
581
  ...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
417
582
  auth: { username: this.userToken, password: '' }
418
583
  }),
@@ -420,29 +585,110 @@ class SonarqubeResults {
420
585
  headers: { Authorization: `Bearer ${this.userToken}` }
421
586
  }),
422
587
  params: {
423
- componentKeys: this.projectKey,
424
- statuses: 'OPEN,REOPENED,CONFIRMED,RESOLVED',
588
+ component: component,
589
+ strategy: 'children',
425
590
  p: page,
591
+ ps: pageSize,
426
592
  ...(this.branchName && { branch: this.branchName }),
427
593
  ...(this.pullRequestID && { pullRequest: this.pullRequestID })
428
594
  }
429
- })
430
- .then(({ data }) => {
431
- _.mergeWith(results, data, (objValue, srcValue) => _.isArray(objValue) ? objValue.concat(srcValue) : undefined);
432
- paging =
433
- data.paging.pageIndex * data.paging.pageSize <= data.paging.total;
434
- page += 1;
435
- })
436
- .catch((e) => {
437
- this.logAxiosError(e);
438
- return Promise.reject(new Error('Failed at getting Sonarqube issue'));
439
595
  });
596
+ };
597
+ // intentionally doing the await in a loop so as to slow down requests a tad bit in order to avoid any rate limit issues
598
+ const collectPagedSearch = async (component, sizeCheck = false) => {
599
+ let paging = true;
600
+ let page = 1;
601
+ const results = {
602
+ components: [],
603
+ effortTotal: 0,
604
+ facets: [],
605
+ issues: [],
606
+ paging: { pageIndex: 0, pageSize: 0, total: 0 }
607
+ };
608
+ while (sizeCheck ? page === 1 : paging) {
609
+ console.log(results);
610
+ await createSearch(component, page)
611
+ .then(({ data }) => {
612
+ _.mergeWith(results, data, (objValue, srcValue) => _.isArray(objValue) ? objValue.concat(srcValue) : undefined);
613
+ // only need to check if it exceeds the upper limit, if it's less than the upper limit and we request a page that goes past the page total then it just returns fewer results without throwing an error
614
+ paging =
615
+ data.paging.pageIndex * data.paging.pageSize <= data.paging.total;
616
+ page += 1;
617
+ })
618
+ .catch((e) => {
619
+ this.logAxiosError(e);
620
+ throw new Error('Failed at retrieving Sonarqube issues');
621
+ });
622
+ if (page * PAGE_SIZE > UPPER_LIMIT) {
623
+ logger.warn(`Exceeded SonarQube cap of ${UPPER_LIMIT} results for findings of or under the ${component} component. Remaining findings may be truncated.`);
624
+ paging = false;
625
+ }
626
+ }
627
+ results.components = _.uniqBy(results.components, 'key'); // sometimes components will be duplicated if an issue on one page applies to the same component as an issue on another page. additionally at minimum the top level project will show up in every search result
628
+ return results;
629
+ };
630
+ const collectPagedComponentSearch = async (component) => {
631
+ let paging = true;
632
+ let page = 1;
633
+ const results = {
634
+ paging: { pageIndex: 0, pageSize: 0, total: 0 },
635
+ baseComponent: {
636
+ key: 'fake',
637
+ description: 'fake',
638
+ qualifier: 'fake',
639
+ tags: [],
640
+ visibility: 'false'
641
+ },
642
+ components: []
643
+ };
644
+ while (paging) {
645
+ await createComponentSearch(component, page)
646
+ .then(({ data }) => {
647
+ _.mergeWith(results, data, (objValue, srcValue) => _.isArray(objValue) ? objValue.concat(srcValue) : undefined);
648
+ paging =
649
+ data.paging.pageIndex * data.paging.pageSize <= data.paging.total;
650
+ page += 1;
651
+ })
652
+ .catch((e) => {
653
+ this.logAxiosError(e);
654
+ throw new Error('Failed at retrieving the list of components');
655
+ });
656
+ if (page * PAGE_SIZE > UPPER_LIMIT) {
657
+ logger.warn(`Exceeded SonarQube cap of ${UPPER_LIMIT} results for the search for children of the ${component} component. Remaining set of components may be truncated.`);
658
+ paging = false;
659
+ }
660
+ }
661
+ return results;
662
+ };
663
+ const results = await collectPagedSearch(this.projectKey, true);
664
+ const queue = [this.projectKey];
665
+ while (queue.length > 0) {
666
+ const component = queue.shift();
667
+ if (component === undefined) {
668
+ // unreachable code since we check that there are items in the queue; however, it helps typescript narrow the type properly
669
+ continue;
670
+ }
671
+ const sizeCheck = await collectPagedSearch(component, true);
672
+ if (sizeCheck.paging.total > UPPER_LIMIT) {
673
+ const componentSearch = await collectPagedComponentSearch(component);
674
+ queue.push(...componentSearch.components.map((c) => c.key));
675
+ }
676
+ const componentResults = await collectPagedSearch(component);
677
+ _.mergeWith(results, componentResults, (objValue, srcValue) => _.isArray(objValue) ? objValue.concat(srcValue) : objValue);
678
+ }
679
+ results.components = _.uniqBy(results.components, 'key');
680
+ results.issues = _.uniqBy(results.issues, 'key');
681
+ if (results.paging.total === results.issues.length) {
682
+ logger.warn('Alternative search queries were able to retrieve all findings.');
683
+ }
684
+ else {
685
+ logger.warn(`Alternative search queries were not able to retrieve all findings - ${results.paging.total - results.issues.length} findings were not retrieved.`);
440
686
  }
441
687
  return results;
442
688
  }
443
689
  async getCodeSnippets(issues) {
444
690
  const getFullFile = async (component) => {
445
- return axios_1.default
691
+ return this.axiosClient
446
692
  .get(`${this.sonarqubeHost}/api/sources/raw`, {
447
693
  ...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
448
694
  auth: { username: this.userToken, password: '' }
@@ -471,7 +717,7 @@ class SonarqubeResults {
471
717
  const linenumberedFile = applyLineNumber(fullFiles[component]);
472
718
  const snippet = linenumberedFile
473
719
  .split('\n')
474
- .slice(Math.max(startLine - 3, 0), endLine + 3)
720
+ .slice(Math.max(startLine - 3, 0), endLine + 3) // slice wraps around if the start is less than 0 so we want to put a bounds check there to ensure we start at the top of the file; however, if the end is past the end of the array then it just goes until the end of the array so no bounds check is required there
475
721
  .join('\n')
476
722
  .trim();
477
723
  const location = `${component}:${startLine}-${endLine}\n`;
@@ -483,15 +729,23 @@ class SonarqubeResults {
483
729
  : [issue.component]));
484
730
  const fullFilePromises = await Promise.all(components.map((component) => getFullFile(component)));
485
731
  const fullFiles = Object.fromEntries(_.zip(components, fullFilePromises));
486
- const snippets = issues.map((issue) => issue.flows.length
487
- ? issue.flows
488
- .flatMap((flow) => flow.locations.map((location) => getContextualizedSnippet(fullFiles, location.component, location.textRange.startLine, location.textRange.endLine, location.msg)))
489
- .join('\n')
490
- : getContextualizedSnippet(fullFiles, issue.component, issue.textRange.startLine, issue.textRange.endLine));
732
+ const snippets = issues.map((issue) => {
733
+ if (issue.flows.length) {
734
+ return issue.flows
735
+ .flatMap((flow) => flow.locations.map((location) => getContextualizedSnippet(fullFiles, location.component, location.textRange.startLine, location.textRange.endLine, location.msg)))
736
+ .join('\n');
737
+ }
738
+ else if (issue.textRange) {
739
+ return getContextualizedSnippet(fullFiles, issue.component, issue.textRange.startLine, issue.textRange.endLine);
740
+ }
741
+ else {
742
+ return '';
743
+ }
744
+ });
491
745
  return snippets;
492
746
  }
493
747
  async getRules(issues) {
494
- const getRule = async (rule, organization) => axios_1.default
748
+ const getRule = async (rule, organization) => this.axiosClient
495
749
  .get(`${this.sonarqubeHost}/api/rules/show`, {
496
750
  ...(this.authMethod === AuthenticationMethod.TokenAsUsername && {
497
751
  auth: { username: this.userToken, password: '' }
@@ -503,7 +757,7 @@ class SonarqubeResults {
503
757
  key: rule,
504
758
  ...((organization || this.organization) && {
505
759
  organization: organization || this.organization
506
- })
760
+ }) // seems to be required for sonarcloud at least
507
761
  }
508
762
  })
509
763
  .then(({ data }) => data)
@@ -518,7 +772,7 @@ class SonarqubeResults {
518
772
  return rules;
519
773
  }
520
774
  async generateHdf(sonarqubeVersion) {
521
- const searchResults = await this.getSearchResults();
775
+ const searchResults = await this.getSearchResults(sonarqubeVersion);
522
776
  logger.debug(`Got ${searchResults.issues.length} issues`);
523
777
  const codeSnippets = await this.getCodeSnippets(searchResults.issues);
524
778
  logger.debug(`Got ${codeSnippets.length} code snippets`);
@@ -543,7 +797,7 @@ class SonarqubeResults {
543
797
  return new SonarqubeMapper(data, this.withRaw).toHdf();
544
798
  }
545
799
  async toHdf() {
546
- const sonarqubeVersion = await axios_1.default
800
+ const sonarqubeVersion = await this.axiosClient
547
801
  .get(`${this.sonarqubeHost}/api/server/version`)
548
802
  .then(({ data }) => data);
549
803
  logger.debug(`Generating HDF for ${this.sonarqubeHost} version: ${sonarqubeVersion}`);