@quantakrypto/core 0.4.3 → 0.5.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 (314) hide show
  1. package/README.md +76 -27
  2. package/dist/cbom-merge.d.ts +9 -0
  3. package/dist/cbom-merge.d.ts.map +1 -0
  4. package/dist/cbom-merge.js +121 -0
  5. package/dist/cbom-merge.js.map +1 -0
  6. package/dist/cbom.d.ts +5 -0
  7. package/dist/cbom.d.ts.map +1 -1
  8. package/dist/cbom.js +132 -37
  9. package/dist/cbom.js.map +1 -1
  10. package/dist/comments.d.ts +6 -26
  11. package/dist/comments.d.ts.map +1 -1
  12. package/dist/comments.js +77 -38
  13. package/dist/comments.js.map +1 -1
  14. package/dist/dependencies.d.ts.map +1 -1
  15. package/dist/dependencies.js +1 -1
  16. package/dist/dependencies.js.map +1 -1
  17. package/dist/detect-utils.d.ts +59 -21
  18. package/dist/detect-utils.d.ts.map +1 -1
  19. package/dist/detect-utils.js +143 -8
  20. package/dist/detect-utils.js.map +1 -1
  21. package/dist/detectors/age.d.ts +16 -0
  22. package/dist/detectors/age.d.ts.map +1 -0
  23. package/dist/detectors/age.js +40 -0
  24. package/dist/detectors/age.js.map +1 -0
  25. package/dist/detectors/ansible.d.ts +13 -0
  26. package/dist/detectors/ansible.d.ts.map +1 -0
  27. package/dist/detectors/ansible.js +108 -0
  28. package/dist/detectors/ansible.js.map +1 -0
  29. package/dist/detectors/bicep.d.ts +20 -0
  30. package/dist/detectors/bicep.d.ts.map +1 -0
  31. package/dist/detectors/bicep.js +74 -0
  32. package/dist/detectors/bicep.js.map +1 -0
  33. package/dist/detectors/c.d.ts +4 -2
  34. package/dist/detectors/c.d.ts.map +1 -1
  35. package/dist/detectors/c.js +222 -4
  36. package/dist/detectors/c.js.map +1 -1
  37. package/dist/detectors/cicd.d.ts +27 -0
  38. package/dist/detectors/cicd.d.ts.map +1 -0
  39. package/dist/detectors/cicd.js +129 -0
  40. package/dist/detectors/cicd.js.map +1 -0
  41. package/dist/detectors/cloud-kms.d.ts +24 -0
  42. package/dist/detectors/cloud-kms.d.ts.map +1 -0
  43. package/dist/detectors/cloud-kms.js +99 -0
  44. package/dist/detectors/cloud-kms.js.map +1 -0
  45. package/dist/detectors/cloudformation.d.ts +38 -0
  46. package/dist/detectors/cloudformation.d.ts.map +1 -0
  47. package/dist/detectors/cloudformation.js +201 -0
  48. package/dist/detectors/cloudformation.js.map +1 -0
  49. package/dist/detectors/codesign.d.ts +50 -0
  50. package/dist/detectors/codesign.d.ts.map +1 -0
  51. package/dist/detectors/codesign.js +143 -0
  52. package/dist/detectors/codesign.js.map +1 -0
  53. package/dist/detectors/csharp.d.ts.map +1 -1
  54. package/dist/detectors/csharp.js +13 -3
  55. package/dist/detectors/csharp.js.map +1 -1
  56. package/dist/detectors/dart.d.ts +35 -0
  57. package/dist/detectors/dart.d.ts.map +1 -0
  58. package/dist/detectors/dart.js +177 -0
  59. package/dist/detectors/dart.js.map +1 -0
  60. package/dist/detectors/database.d.ts +19 -0
  61. package/dist/detectors/database.d.ts.map +1 -0
  62. package/dist/detectors/database.js +97 -0
  63. package/dist/detectors/database.js.map +1 -0
  64. package/dist/detectors/dkim.d.ts +54 -0
  65. package/dist/detectors/dkim.d.ts.map +1 -0
  66. package/dist/detectors/dkim.js +92 -0
  67. package/dist/detectors/dkim.js.map +1 -0
  68. package/dist/detectors/dnssec.d.ts +55 -0
  69. package/dist/detectors/dnssec.d.ts.map +1 -0
  70. package/dist/detectors/dnssec.js +116 -0
  71. package/dist/detectors/dnssec.js.map +1 -0
  72. package/dist/detectors/elixir.d.ts +20 -0
  73. package/dist/detectors/elixir.d.ts.map +1 -0
  74. package/dist/detectors/elixir.js +227 -0
  75. package/dist/detectors/elixir.js.map +1 -0
  76. package/dist/detectors/java.d.ts.map +1 -1
  77. package/dist/detectors/java.js +34 -4
  78. package/dist/detectors/java.js.map +1 -1
  79. package/dist/detectors/jose.d.ts +20 -0
  80. package/dist/detectors/jose.d.ts.map +1 -0
  81. package/dist/detectors/jose.js +72 -0
  82. package/dist/detectors/jose.js.map +1 -0
  83. package/dist/detectors/jwk.d.ts +25 -0
  84. package/dist/detectors/jwk.d.ts.map +1 -0
  85. package/dist/detectors/jwk.js +131 -0
  86. package/dist/detectors/jwk.js.map +1 -0
  87. package/dist/detectors/k8s.d.ts +17 -0
  88. package/dist/detectors/k8s.d.ts.map +1 -0
  89. package/dist/detectors/k8s.js +88 -0
  90. package/dist/detectors/k8s.js.map +1 -0
  91. package/dist/detectors/keystore.d.ts +19 -0
  92. package/dist/detectors/keystore.d.ts.map +1 -0
  93. package/dist/detectors/keystore.js +76 -0
  94. package/dist/detectors/keystore.js.map +1 -0
  95. package/dist/detectors/mesh.d.ts +34 -0
  96. package/dist/detectors/mesh.d.ts.map +1 -0
  97. package/dist/detectors/mesh.js +91 -0
  98. package/dist/detectors/mesh.js.map +1 -0
  99. package/dist/detectors/messaging.d.ts +16 -0
  100. package/dist/detectors/messaging.d.ts.map +1 -0
  101. package/dist/detectors/messaging.js +79 -0
  102. package/dist/detectors/messaging.js.map +1 -0
  103. package/dist/detectors/objc.d.ts +41 -0
  104. package/dist/detectors/objc.d.ts.map +1 -0
  105. package/dist/detectors/objc.js +146 -0
  106. package/dist/detectors/objc.js.map +1 -0
  107. package/dist/detectors/openpgp.d.ts +20 -0
  108. package/dist/detectors/openpgp.d.ts.map +1 -0
  109. package/dist/detectors/openpgp.js +151 -0
  110. package/dist/detectors/openpgp.js.map +1 -0
  111. package/dist/detectors/pem.d.ts.map +1 -1
  112. package/dist/detectors/pem.js +33 -1
  113. package/dist/detectors/pem.js.map +1 -1
  114. package/dist/detectors/php.d.ts +25 -0
  115. package/dist/detectors/php.d.ts.map +1 -0
  116. package/dist/detectors/php.js +171 -0
  117. package/dist/detectors/php.js.map +1 -0
  118. package/dist/detectors/pkcs11.d.ts +17 -0
  119. package/dist/detectors/pkcs11.d.ts.map +1 -0
  120. package/dist/detectors/pkcs11.js +87 -0
  121. package/dist/detectors/pkcs11.js.map +1 -0
  122. package/dist/detectors/proxy.d.ts +52 -0
  123. package/dist/detectors/proxy.d.ts.map +1 -0
  124. package/dist/detectors/proxy.js +157 -0
  125. package/dist/detectors/proxy.js.map +1 -0
  126. package/dist/detectors/pulumi.d.ts +19 -0
  127. package/dist/detectors/pulumi.d.ts.map +1 -0
  128. package/dist/detectors/pulumi.js +80 -0
  129. package/dist/detectors/pulumi.js.map +1 -0
  130. package/dist/detectors/python.d.ts.map +1 -1
  131. package/dist/detectors/python.js +70 -0
  132. package/dist/detectors/python.js.map +1 -1
  133. package/dist/detectors/rust.d.ts.map +1 -1
  134. package/dist/detectors/rust.js +73 -0
  135. package/dist/detectors/rust.js.map +1 -1
  136. package/dist/detectors/secrets.d.ts +24 -0
  137. package/dist/detectors/secrets.d.ts.map +1 -0
  138. package/dist/detectors/secrets.js +63 -0
  139. package/dist/detectors/secrets.js.map +1 -0
  140. package/dist/detectors/solidity.d.ts +50 -0
  141. package/dist/detectors/solidity.d.ts.map +1 -0
  142. package/dist/detectors/solidity.js +108 -0
  143. package/dist/detectors/solidity.js.map +1 -0
  144. package/dist/detectors/source.d.ts.map +1 -1
  145. package/dist/detectors/source.js +243 -53
  146. package/dist/detectors/source.js.map +1 -1
  147. package/dist/detectors/spire.d.ts +49 -0
  148. package/dist/detectors/spire.d.ts.map +1 -0
  149. package/dist/detectors/spire.js +77 -0
  150. package/dist/detectors/spire.js.map +1 -0
  151. package/dist/detectors/ssh-ca.d.ts +72 -0
  152. package/dist/detectors/ssh-ca.d.ts.map +1 -0
  153. package/dist/detectors/ssh-ca.js +119 -0
  154. package/dist/detectors/ssh-ca.js.map +1 -0
  155. package/dist/detectors/stateful-hbs.d.ts.map +1 -1
  156. package/dist/detectors/stateful-hbs.js +9 -6
  157. package/dist/detectors/stateful-hbs.js.map +1 -1
  158. package/dist/detectors/supply-chain.d.ts +17 -0
  159. package/dist/detectors/supply-chain.d.ts.map +1 -0
  160. package/dist/detectors/supply-chain.js +89 -0
  161. package/dist/detectors/supply-chain.js.map +1 -0
  162. package/dist/detectors/swift.d.ts +22 -0
  163. package/dist/detectors/swift.d.ts.map +1 -0
  164. package/dist/detectors/swift.js +120 -0
  165. package/dist/detectors/swift.js.map +1 -0
  166. package/dist/detectors/terraform.d.ts +21 -0
  167. package/dist/detectors/terraform.d.ts.map +1 -0
  168. package/dist/detectors/terraform.js +150 -0
  169. package/dist/detectors/terraform.js.map +1 -0
  170. package/dist/detectors/vault.d.ts +15 -0
  171. package/dist/detectors/vault.d.ts.map +1 -0
  172. package/dist/detectors/vault.js +97 -0
  173. package/dist/detectors/vault.js.map +1 -0
  174. package/dist/detectors/vpn.d.ts +22 -0
  175. package/dist/detectors/vpn.d.ts.map +1 -0
  176. package/dist/detectors/vpn.js +73 -0
  177. package/dist/detectors/vpn.js.map +1 -0
  178. package/dist/detectors/weak-hash.d.ts +71 -0
  179. package/dist/detectors/weak-hash.d.ts.map +1 -0
  180. package/dist/detectors/weak-hash.js +116 -0
  181. package/dist/detectors/weak-hash.js.map +1 -0
  182. package/dist/detectors/webauthn.d.ts +61 -0
  183. package/dist/detectors/webauthn.d.ts.map +1 -0
  184. package/dist/detectors/webauthn.js +109 -0
  185. package/dist/detectors/webauthn.js.map +1 -0
  186. package/dist/detectors/xmldsig.d.ts +23 -0
  187. package/dist/detectors/xmldsig.d.ts.map +1 -0
  188. package/dist/detectors/xmldsig.js +84 -0
  189. package/dist/detectors/xmldsig.js.map +1 -0
  190. package/dist/evidence.d.ts +79 -4
  191. package/dist/evidence.d.ts.map +1 -1
  192. package/dist/evidence.js +76 -0
  193. package/dist/evidence.js.map +1 -1
  194. package/dist/index.d.ts +17 -9
  195. package/dist/index.d.ts.map +1 -1
  196. package/dist/index.js +21 -9
  197. package/dist/index.js.map +1 -1
  198. package/dist/inventory.d.ts +0 -2
  199. package/dist/inventory.d.ts.map +1 -1
  200. package/dist/inventory.js +15 -6
  201. package/dist/inventory.js.map +1 -1
  202. package/dist/policy.d.ts +67 -0
  203. package/dist/policy.d.ts.map +1 -0
  204. package/dist/policy.js +115 -0
  205. package/dist/policy.js.map +1 -0
  206. package/dist/registry.d.ts +9 -4
  207. package/dist/registry.d.ts.map +1 -1
  208. package/dist/registry.js +81 -4
  209. package/dist/registry.js.map +1 -1
  210. package/dist/remediate-pipeline.d.ts +0 -3
  211. package/dist/remediate-pipeline.d.ts.map +1 -1
  212. package/dist/remediate-pipeline.js +23 -2
  213. package/dist/remediate-pipeline.js.map +1 -1
  214. package/dist/remediation.d.ts +10 -0
  215. package/dist/remediation.d.ts.map +1 -1
  216. package/dist/remediation.js +32 -0
  217. package/dist/remediation.js.map +1 -1
  218. package/dist/report.d.ts +9 -0
  219. package/dist/report.d.ts.map +1 -1
  220. package/dist/report.js +38 -1
  221. package/dist/report.js.map +1 -1
  222. package/dist/scan-worker.js +5 -3
  223. package/dist/scan-worker.js.map +1 -1
  224. package/dist/scan.d.ts.map +1 -1
  225. package/dist/scan.js +35 -6
  226. package/dist/scan.js.map +1 -1
  227. package/dist/standards-profiles.d.ts +58 -0
  228. package/dist/standards-profiles.d.ts.map +1 -0
  229. package/dist/standards-profiles.js +100 -0
  230. package/dist/standards-profiles.js.map +1 -0
  231. package/dist/standards.d.ts +96 -0
  232. package/dist/standards.d.ts.map +1 -0
  233. package/dist/standards.js +107 -0
  234. package/dist/standards.js.map +1 -0
  235. package/dist/types.d.ts +6 -5
  236. package/dist/types.d.ts.map +1 -1
  237. package/dist/types.js.map +1 -1
  238. package/dist/version.d.ts +1 -1
  239. package/dist/version.js +1 -1
  240. package/dist/version.js.map +1 -1
  241. package/dist/vex.d.ts +39 -0
  242. package/dist/vex.d.ts.map +1 -0
  243. package/dist/vex.js +87 -0
  244. package/dist/vex.js.map +1 -0
  245. package/dist/walk.d.ts +8 -3
  246. package/dist/walk.d.ts.map +1 -1
  247. package/dist/walk.js +32 -1
  248. package/dist/walk.js.map +1 -1
  249. package/package.json +1 -1
  250. package/src/cbom-merge.ts +146 -0
  251. package/src/cbom.ts +153 -39
  252. package/src/comments.ts +84 -39
  253. package/src/dependencies.ts +2 -1
  254. package/src/detect-utils.ts +146 -12
  255. package/src/detectors/age.ts +60 -0
  256. package/src/detectors/ansible.ts +140 -0
  257. package/src/detectors/bicep.ts +107 -0
  258. package/src/detectors/c.ts +240 -6
  259. package/src/detectors/cicd.ts +171 -0
  260. package/src/detectors/cloud-kms.ts +141 -0
  261. package/src/detectors/cloudformation.ts +250 -0
  262. package/src/detectors/codesign.ts +214 -0
  263. package/src/detectors/csharp.ts +13 -3
  264. package/src/detectors/dart.ts +237 -0
  265. package/src/detectors/database.ts +141 -0
  266. package/src/detectors/dkim.ts +172 -0
  267. package/src/detectors/dnssec.ts +195 -0
  268. package/src/detectors/elixir.ts +268 -0
  269. package/src/detectors/java.ts +39 -4
  270. package/src/detectors/jose.ts +110 -0
  271. package/src/detectors/jwk.ts +170 -0
  272. package/src/detectors/k8s.ts +115 -0
  273. package/src/detectors/keystore.ts +109 -0
  274. package/src/detectors/mesh.ts +130 -0
  275. package/src/detectors/messaging.ts +106 -0
  276. package/src/detectors/objc.ts +209 -0
  277. package/src/detectors/openpgp.ts +194 -0
  278. package/src/detectors/pem.ts +31 -1
  279. package/src/detectors/php.ts +230 -0
  280. package/src/detectors/pkcs11.ts +113 -0
  281. package/src/detectors/proxy.ts +236 -0
  282. package/src/detectors/pulumi.ts +106 -0
  283. package/src/detectors/python.ts +71 -0
  284. package/src/detectors/rust.ts +76 -0
  285. package/src/detectors/secrets.ts +103 -0
  286. package/src/detectors/solidity.ts +176 -0
  287. package/src/detectors/source.ts +283 -73
  288. package/src/detectors/spire.ts +143 -0
  289. package/src/detectors/ssh-ca.ts +215 -0
  290. package/src/detectors/stateful-hbs.ts +9 -6
  291. package/src/detectors/supply-chain.ts +117 -0
  292. package/src/detectors/swift.ts +149 -0
  293. package/src/detectors/terraform.ts +188 -0
  294. package/src/detectors/vault.ts +120 -0
  295. package/src/detectors/vpn.ts +103 -0
  296. package/src/detectors/weak-hash.ts +217 -0
  297. package/src/detectors/webauthn.ts +205 -0
  298. package/src/detectors/xmldsig.ts +115 -0
  299. package/src/evidence.ts +138 -4
  300. package/src/index.ts +50 -12
  301. package/src/inventory.ts +15 -7
  302. package/src/policy.ts +180 -0
  303. package/src/registry.ts +81 -4
  304. package/src/remediate-pipeline.ts +26 -3
  305. package/src/remediation.ts +39 -0
  306. package/src/report.ts +43 -1
  307. package/src/scan-worker.ts +5 -3
  308. package/src/scan.ts +41 -6
  309. package/src/standards-profiles.ts +136 -0
  310. package/src/standards.ts +186 -0
  311. package/src/types.ts +11 -4
  312. package/src/version.ts +1 -1
  313. package/src/vex.ts +122 -0
  314. package/src/walk.ts +33 -2
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AA6BtE,MAAM,YAAY,GAChB,gGAAgG,CAAC;AAEnG,MAAM,eAAe,GAAG,2CAA2C,CAAC;AAEpE;;;;GAIG;AACH,SAAS,cAAc,CAAC,CAAU,EAAE,cAAuB;IACzD,IAAI,cAAc,IAAI,CAAC,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACpD,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;AAC5B,CAAC;AAED,6FAA6F;AAC7F,SAAS,SAAS,CAAC,QAAkB;IACnC,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,UAAU;YACb,OAAO,GAAG,CAAC;QACb,KAAK,MAAM;YACT,OAAO,EAAE,CAAC;QACZ,KAAK,QAAQ;YACX,OAAO,EAAE,CAAC;QACZ,KAAK,KAAK;YACR,OAAO,EAAE,CAAC;QACZ;YACE,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,SAAS,SAAS,CAAC,IAUlB;IACC,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,EAAE;QACb,gBAAgB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;QACtC,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE;QACvC,oBAAoB,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;QAC1F,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,gBAAgB,IAAI,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnF,UAAU,EAAE;YACV,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,mBAAmB,EAAE,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5F,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtD;QACD,GAAG,CAAC,IAAI,CAAC,GAAG;YACV,CAAC,CAAC;gBACE,aAAa,EAAE;oBACb,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE;iBAClF;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,OAAO,CAAC,MAAkB,EAAE,IAAoB;IAC9D,MAAM,cAAc,GAAG,IAAI,EAAE,cAAc,IAAI,KAAK,CAAC;IACrD,6EAA6E;IAC7E,+EAA+E;IAC/E,6EAA6E;IAC7E,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,MAAM,KAAK,GAAmC,EAAE,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,OAAO,IAAI,EAAE,EAAE,CAAC;QACpC,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAAE,SAAS;QAClC,IAAI,CAAC,CAAC,GAAG;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9B,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAClC,KAAK,CAAC,IAAI,CACR,SAAS,CAAC;YACR,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,WAAW,EAAE,CAAC,CAAC,WAAW;SAC3B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAChC,IAAI,CAAC,CAAC,GAAG;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,SAAS;QACtC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACtC,KAAK,CAAC,IAAI,CACR,SAAS,CAAC;YACR,EAAE,EAAE,CAAC,CAAC,MAAM;YACZ,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,WAAW,EAAE,CAAC,CAAC,WAAW;SAC3B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACxC,MAAM,MAAM,GAA2B,EAAE,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtE,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,QAAQ;YAAE,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;QAClF,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,KAAK,QAAQ;YAAE,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QAChF,MAAM,OAAO,GAAG,cAAc,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QAElD,OAAO;YACL,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;YAClC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC7B,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE;YAC5B,UAAU,EAAE;gBACV,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,UAAU,EAAE,CAAC,CAAC,UAAU;gBACxB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClD,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxD,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACjC;YACD,GAAG,CAAC,CAAC,CAAC,GAAG;gBACP,CAAC,CAAC;oBACE,IAAI,EAAE;wBACJ;4BACE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;yBACtD;qBACF;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,SAAS,EAAE;gBACT;oBACE,gBAAgB,EAAE;wBAChB,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE;wBAC1C,MAAM,EAAE;4BACN,GAAG,MAAM;4BACT,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;yBACnD;qBACF;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,4EAA4E;IAC5E,MAAM,UAAU,GACd,OAAO,CAAC,IAAI,GAAG,CAAC;QACd,CAAC,CAAC;YACE;gBACE,IAAI,EAAE,KAAK;gBACX,cAAc,EAAE,wBAAwB;gBACxC,YAAY,EAAE,OAAO;gBACrB,gBAAgB,EAAE,EAAE,IAAI,EAAE,uCAAuC,EAAE;gBACnE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBACrC,EAAE;oBACF,OAAO,EAAE,0CAA0C,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO;iBAClF,CAAC,CAAC;aACJ;SACF;QACH,CAAC,CAAC,EAAE,CAAC;IAET,OAAO;QACL,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACJ;gBACE,IAAI,EAAE;oBACJ,MAAM,EAAE;wBACN,IAAI,EAAE,OAAO;wBACb,cAAc,EAAE,eAAe;wBAC/B,OAAO,EAAE,MAAM,CAAC,WAAW,IAAI,OAAO;wBACtC,KAAK;qBACN;iBACF;gBACD,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChD,OAAO;aACR;SACF;KACF,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,SAAS,gBAAgB,CAAC,QAAkB;IAC1C,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,UAAU;YACb,OAAO,KAAK,CAAC;QACf,KAAK,MAAM;YACT,OAAO,KAAK,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC;QACf,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,MAAM,CAAC,MAAkB,EAAE,IAAoB;IAC7D,MAAM,cAAc,GAAG,IAAI,EAAE,cAAc,IAAI,KAAK,CAAC;IACrD,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,GAAG,CAAC,MAAM,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,SAAS,EAAE;YACT,cAAc,EAAE,MAAM,CAAC,SAAS,CAAC,cAAc;YAC/C,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,SAAS;YACrC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,UAAU;YACvC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,UAAU;YACvC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW;SAC1C;QACD,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,QAAQ,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI;gBACrB,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI;gBACrB,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM;gBACzB,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO;gBAC3B,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,cAAc,CAAC;aAC3C;SACF,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAEhF,8DAA8D;AAC9D,MAAM,IAAI,GAAG;IACX,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,UAAU;IACf,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,UAAU;IAClB,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,UAAU;IACnB,IAAI,EAAE,UAAU;CACR,CAAC;AAEX,SAAS,aAAa,CAAC,GAAa;IAClC,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,UAAU;YACb,OAAO,IAAI,CAAC,OAAO,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,IAAI,CAAC,GAAG,CAAC;QAClB,KAAK,QAAQ;YACX,OAAO,IAAI,CAAC,MAAM,CAAC;QACrB,KAAK,KAAK;YACR,OAAO,IAAI,CAAC,IAAI,CAAC;QACnB;YACE,OAAO,IAAI,CAAC,GAAG,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC;IACnC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC,MAAM,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAkB,EAClB,OAAkD;IAElD,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,KAAK,CAAC;IACtC,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,IAAY,EAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEjG,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC;IAE7B,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,uCAAuC,CAAC,CAAC,CAAC;IAClE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,MAAM,CAAC,WAAW,YAAY,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,0BAA0B;IAC1B,KAAK,CAAC,IAAI,CACR,oBAAoB,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,cAAc,MAAM,CAAC,EAAE,CACtG,CAAC;IACF,MAAM,QAAQ,GACZ,MAAM,CAAC,aAAa,KAAK,SAAS;QAChC,CAAC,CAAC,gBAAgB,0BAA0B,MAAM,MAAM,CAAC,aAAa,EAAE;QACxE,CAAC,CAAC,EAAE,CAAC;IACT,KAAK,CAAC,IAAI,CACR,oBAAoB,MAAM,CAAC,YAAY,GAAG,QAAQ,gBAAgB,MAAM,CAAC,QAAQ,CAAC,MAAM,oBAAoB,CAAC,CAC3G,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EACzC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CACtB,EAAE,CACJ,CAAC;IACF,sFAAsF;IACtF,IAAI,MAAM,CAAC,aAAa,KAAK,CAAC,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;QAC1D,KAAK,CAAC,IAAI,CACR,CAAC,CACC,IAAI,CAAC,MAAM,EACX,sDAAsD,0BAA0B,yDAAyD,CAC1I,CACF,CAAC;IACJ,CAAC;IACD,gFAAgF;IAChF,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;IAChC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,EAAE,CAAC;QAC9D,KAAK,CAAC,IAAI,CACR,CAAC,CACC,IAAI,CAAC,MAAM,EACX,aAAa,IAAI,CAAC,UAAU,gBAAgB,IAAI,CAAC,eAAe,mDAAmD,CACpH,CACF,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,sBAAsB;IACtB,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC7E,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAClD,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,iBAAiB,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAE9F,uBAAuB;IACvB,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;SAC9C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3B,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjC,IAAI,SAAS,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,kDAAkD,CAAC,CAAC,CAAC;QAC9E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,iFAAiF;IACjF,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAClF,CAAC;IACF,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,KAAK,CAAC,IAAI,CACR,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,IAAI,CAAC,CAC1F,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,GAC/C,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAChD,EAAE,CAAC;QACH,MAAM,GAAG,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI,EAAE,CAAC,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACvD,IAAI,CAAC,CAAC,WAAW;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,MAAM,CAAC,MAAM,GAAG,SAAS,QAAQ,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CACR,CAAC,CACC,IAAI,CAAC,MAAM,EACX,SAAS,GAAG,CAAC,SAAS,4DAA4D;YAChF,oFAAoF;YACpF,gFAAgF,CACnF,CACF,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,kBAAkB,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,WAAmC,EACnC,IAAkB;IAElB,MAAM,KAAK,GAAG,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,yBAAyB,CAAC;IAC1F,MAAM,GAAG,GAAa,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACrB,MAAM,GAAG,GAAG,CAAoB,CAAC;QACjC,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,yBAAyB;QAClF,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1C,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;YAAE,SAAS;QAC3C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,GAAG,CAAC,IAAI,CACN,0HAA0H,CAC3H,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * Reporters: turn a {@link ScanResult} into SARIF 2.1.0, a clean JSON object,\n * or a human-readable text summary. No third-party dependencies — ANSI colour\n * is emitted with raw escape codes and is off by default.\n */\nimport type { AlgorithmFamily, Finding, RuleMeta, ScanResult, Severity } from \"./types.js\";\nimport { VERSION } from \"./version.js\";\nimport { SEVERITY_ORDER, sarifLevel } from \"./severity.js\";\nimport { ANALYZABLE_LANGUAGES_LABEL } from \"./detect-utils.js\";\nimport { remediationFor, remediationForTier } from \"./remediation.js\";\nimport type { SecurityTier } from \"./remediation.js\";\n\n/** Minimal SARIF 2.1.0 log shape (kept permissive on purpose). */\nexport interface SarifLog {\n $schema: string;\n version: \"2.1.0\";\n runs: unknown[];\n}\n\n/** Options shared by the structured reporters ({@link toSarif} / {@link toJson}). */\nexport interface ReportOptions {\n /**\n * Omit `location.snippet` from every finding in the output. Defaults to false\n * (snippets are included). Snippets of `sensitive` findings (e.g. PEM key\n * blocks, SSH public keys) are ALWAYS omitted regardless of this flag — the\n * snippet there IS the sensitive value.\n */\n redactSnippets?: boolean;\n /**\n * Full rule catalog to advertise in SARIF `tool.driver.rules[]`, even for\n * rules that produced no finding in this run. Pass\n * `defaultRegistry.ruleCatalog()`. When omitted, only the rules that actually\n * fired are emitted (the historical behaviour). SARIF-only; ignored by\n * {@link toJson}.\n */\n catalog?: RuleMeta[];\n}\n\nconst SARIF_SCHEMA =\n \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\";\n\nconst INFORMATION_URI = \"https://github.com/quantakrypto/pqc-tools\";\n\n/**\n * Resolve the snippet to emit for a finding, honouring redaction. Sensitive\n * findings (key material) never expose their snippet; otherwise the snippet is\n * dropped only when `redactSnippets` is set.\n */\nfunction emittedSnippet(f: Finding, redactSnippets: boolean): string | undefined {\n if (redactSnippets || f.sensitive) return undefined;\n return f.location.snippet;\n}\n\n/** Map our severity to a SARIF rule-level default (used in rules[].defaultConfiguration). */\nfunction sarifRank(severity: Severity): number {\n switch (severity) {\n case \"critical\":\n return 100;\n case \"high\":\n return 80;\n case \"medium\":\n return 50;\n case \"low\":\n return 20;\n default:\n return 5;\n }\n}\n\n/** Build a SARIF `rules[]` entry from a rule's severity/title/message/etc. */\nfunction sarifRule(spec: {\n id: string;\n title: string;\n message: string;\n severity: Severity;\n category: string;\n algorithm?: string;\n hndl: boolean;\n cwe?: string;\n remediation?: string;\n}): Record<string, unknown> {\n return {\n id: spec.id,\n name: spec.id,\n shortDescription: { text: spec.title },\n fullDescription: { text: spec.message },\n defaultConfiguration: { level: sarifLevel(spec.severity), rank: sarifRank(spec.severity) },\n ...(spec.remediation ? { help: { text: `Remediation: ${spec.remediation}` } } : {}),\n properties: {\n category: spec.category,\n ...(spec.algorithm ? { algorithm: spec.algorithm } : {}),\n hndl: spec.hndl,\n ...(spec.cwe ? { cwe: spec.cwe, \"security-severity\": securitySeverity(spec.severity) } : {}),\n ...(spec.cwe ? { tags: [\"security\", spec.cwe] } : {}),\n },\n ...(spec.cwe\n ? {\n relationships: [\n { target: { id: spec.cwe, toolComponent: { name: \"CWE\" } }, kinds: [\"relevant\"] },\n ],\n }\n : {}),\n };\n}\n\n/** Serialize a scan result as SARIF 2.1.0. */\nexport function toSarif(result: ScanResult, opts?: ReportOptions): SarifLog {\n const redactSnippets = opts?.redactSnippets ?? false;\n // Build the rule set and collect the CWE taxa referenced by any rule. When a\n // full catalog is supplied, advertise every rule (even ones that didn't fire);\n // otherwise emit one rule per ruleId encountered (the historical behaviour).\n const ruleIndex = new Map<string, number>();\n const rules: Array<Record<string, unknown>> = [];\n const cweTaxa = new Set<string>();\n\n for (const r of opts?.catalog ?? []) {\n if (ruleIndex.has(r.id)) continue;\n if (r.cwe) cweTaxa.add(r.cwe);\n ruleIndex.set(r.id, rules.length);\n rules.push(\n sarifRule({\n id: r.id,\n title: r.title,\n message: r.message,\n severity: r.severity,\n category: r.category,\n algorithm: r.algorithm,\n hndl: r.hndl,\n cwe: r.cwe,\n remediation: r.remediation,\n }),\n );\n }\n\n for (const f of result.findings) {\n if (f.cwe) cweTaxa.add(f.cwe);\n if (ruleIndex.has(f.ruleId)) continue;\n ruleIndex.set(f.ruleId, rules.length);\n rules.push(\n sarifRule({\n id: f.ruleId,\n title: f.title,\n message: f.message,\n severity: f.severity,\n category: f.category,\n algorithm: f.algorithm,\n hndl: f.hndl,\n cwe: f.cwe,\n remediation: f.remediation,\n }),\n );\n }\n\n const results = result.findings.map((f) => {\n const region: Record<string, number> = { startLine: f.location.line };\n if (typeof f.location.column === \"number\") region.startColumn = f.location.column;\n if (typeof f.location.endLine === \"number\") region.endLine = f.location.endLine;\n const snippet = emittedSnippet(f, redactSnippets);\n\n return {\n ruleId: f.ruleId,\n ruleIndex: ruleIndex.get(f.ruleId),\n level: sarifLevel(f.severity),\n message: { text: f.message },\n properties: {\n category: f.category,\n severity: f.severity,\n confidence: f.confidence,\n hndl: f.hndl,\n ...(f.algorithm ? { algorithm: f.algorithm } : {}),\n ...(f.remediation ? { remediation: f.remediation } : {}),\n ...(f.cwe ? { cwe: f.cwe } : {}),\n },\n ...(f.cwe\n ? {\n taxa: [\n {\n target: { id: f.cwe, toolComponent: { name: \"CWE\" } },\n },\n ],\n }\n : {}),\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: f.location.file },\n region: {\n ...region,\n ...(snippet ? { snippet: { text: snippet } } : {}),\n },\n },\n },\n ],\n };\n });\n\n // CWE taxonomy component (SARIF taxonomies), referenced by rules + results.\n const taxonomies =\n cweTaxa.size > 0\n ? [\n {\n name: \"CWE\",\n informationUri: \"https://cwe.mitre.org/\",\n organization: \"MITRE\",\n shortDescription: { text: \"The MITRE Common Weakness Enumeration\" },\n taxa: [...cweTaxa].sort().map((id) => ({\n id,\n helpUri: `https://cwe.mitre.org/data/definitions/${id.replace(/^CWE-/, \"\")}.html`,\n })),\n },\n ]\n : [];\n\n return {\n $schema: SARIF_SCHEMA,\n version: \"2.1.0\",\n runs: [\n {\n tool: {\n driver: {\n name: \"qScan\",\n informationUri: INFORMATION_URI,\n version: result.toolVersion || VERSION,\n rules,\n },\n },\n ...(taxonomies.length > 0 ? { taxonomies } : {}),\n results,\n },\n ],\n };\n}\n\n/** GitHub-code-scanning `security-severity` (0–10) derived from our severity. */\nfunction securitySeverity(severity: Severity): string {\n switch (severity) {\n case \"critical\":\n return \"9.5\";\n case \"high\":\n return \"8.0\";\n case \"medium\":\n return \"5.0\";\n case \"low\":\n return \"3.0\";\n default:\n return \"1.0\";\n }\n}\n\n/** Serialize a scan result as a plain JSON-friendly object. */\nexport function toJson(result: ScanResult, opts?: ReportOptions): Record<string, unknown> {\n const redactSnippets = opts?.redactSnippets ?? false;\n return {\n toolVersion: result.toolVersion,\n root: result.root,\n startedAt: result.startedAt,\n finishedAt: result.finishedAt,\n filesScanned: result.filesScanned,\n ...(result.analyzedFiles !== undefined ? { analyzedFiles: result.analyzedFiles } : {}),\n ...(result.diagnostics ? { diagnostics: result.diagnostics } : {}),\n inventory: {\n readinessScore: result.inventory.readinessScore,\n hndlCount: result.inventory.hndlCount,\n bySeverity: result.inventory.bySeverity,\n byCategory: result.inventory.byCategory,\n byAlgorithm: result.inventory.byAlgorithm,\n },\n findings: result.findings.map((f) => ({\n ruleId: f.ruleId,\n title: f.title,\n category: f.category,\n severity: f.severity,\n confidence: f.confidence,\n algorithm: f.algorithm,\n hndl: f.hndl,\n message: f.message,\n remediation: f.remediation,\n cwe: f.cwe,\n location: {\n file: f.location.file,\n line: f.location.line,\n column: f.location.column,\n endLine: f.location.endLine,\n snippet: emittedSnippet(f, redactSnippets),\n },\n })),\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Human-readable summary */\n/* -------------------------------------------------------------------------- */\n\n/** Raw ANSI codes (no chalk). Disabled when colour is off. */\nconst ANSI = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n} as const;\n\nfunction severityColor(sev: Severity): string {\n switch (sev) {\n case \"critical\":\n return ANSI.magenta;\n case \"high\":\n return ANSI.red;\n case \"medium\":\n return ANSI.yellow;\n case \"low\":\n return ANSI.blue;\n default:\n return ANSI.dim;\n }\n}\n\nfunction scoreColor(score: number): string {\n if (score >= 80) return ANSI.green;\n if (score >= 50) return ANSI.yellow;\n return ANSI.red;\n}\n\n/**\n * Render a human-readable summary of a scan result. Colour is off by default;\n * pass `{ color: true }` to emit ANSI escape codes.\n */\nexport function formatSummary(\n result: ScanResult,\n options?: { color?: boolean; tier?: SecurityTier },\n): string {\n const color = options?.color ?? false;\n const c = (code: string, text: string): string => (color ? `${code}${text}${ANSI.reset}` : text);\n\n const lines: string[] = [];\n const inv = result.inventory;\n\n lines.push(c(ANSI.bold, \"qScan — post-quantum readiness report\"));\n lines.push(c(ANSI.dim, `tool v${result.toolVersion} · root: ${result.root}`));\n lines.push(\"\");\n\n // Readiness score banner.\n lines.push(\n `Readiness score: ${c(`${ANSI.bold}${scoreColor(inv.readinessScore)}`, `${inv.readinessScore}/100`)}`,\n );\n const analyzed =\n result.analyzedFiles !== undefined\n ? ` Analyzed (${ANALYZABLE_LANGUAGES_LABEL}): ${result.analyzedFiles}`\n : \"\";\n lines.push(\n `Files scanned: ${result.filesScanned}${analyzed} Findings: ${result.findings.length} HNDL-exposed: ${c(\n inv.hndlCount > 0 ? ANSI.red : ANSI.green,\n String(inv.hndlCount),\n )}`,\n );\n // Coverage honesty: a score over zero analyzable files is not a clean bill of health.\n if (result.analyzedFiles === 0 && result.filesScanned > 0) {\n lines.push(\n c(\n ANSI.yellow,\n `Note: 0 files were in a supported source language (${ANALYZABLE_LANGUAGES_LABEL}) — the readiness score does not reflect this codebase.`,\n ),\n );\n }\n // Coverage diagnostics: skipped files mean the finding count may be incomplete.\n const diag = result.diagnostics;\n if (diag && (diag.unreadable > 0 || diag.skippedMinified > 0)) {\n lines.push(\n c(\n ANSI.yellow,\n `Coverage: ${diag.unreadable} unreadable, ${diag.skippedMinified} skipped as minified — results may be incomplete.`,\n ),\n );\n }\n lines.push(\"\");\n\n // Severity breakdown.\n const sevParts = SEVERITY_ORDER.filter((s) => inv.bySeverity[s] > 0).map((s) =>\n c(severityColor(s), `${s}: ${inv.bySeverity[s]}`),\n );\n lines.push(`By severity: ${sevParts.length ? sevParts.join(\" \") : c(ANSI.green, \"none\")}`);\n\n // Algorithm breakdown.\n const algoParts = Object.entries(inv.byAlgorithm)\n .sort((a, b) => b[1] - a[1])\n .map(([k, v]) => `${k}: ${v}`);\n if (algoParts.length) lines.push(`By algorithm: ${algoParts.join(\" \")}`);\n lines.push(\"\");\n\n if (result.findings.length === 0) {\n lines.push(c(ANSI.green, \"No classical asymmetric cryptography detected. ✓\"));\n return lines.join(\"\\n\");\n }\n\n // Top findings, grouped by severity (most severe first), capped for readability.\n const sorted = [...result.findings].sort(\n (a, b) => SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity),\n );\n const MAX_SHOWN = 25;\n lines.push(\n c(ANSI.bold, `Top findings (${Math.min(MAX_SHOWN, sorted.length)} of ${sorted.length}):`),\n );\n\n for (const f of sorted.slice(0, MAX_SHOWN)) {\n const loc = `${f.location.file}:${f.location.line}${\n f.location.column ? `:${f.location.column}` : \"\"\n }`;\n const tag = c(severityColor(f.severity), `[${f.severity}]`);\n const hndl = f.hndl ? c(ANSI.red, \" (HNDL)\") : \"\";\n lines.push(` ${tag} ${f.title}${hndl}`);\n lines.push(c(ANSI.dim, ` ${loc} — ${f.message}`));\n if (f.remediation) lines.push(c(ANSI.cyan, ` → ${f.remediation}`));\n }\n\n if (sorted.length > MAX_SHOWN) {\n lines.push(c(ANSI.dim, ` …and ${sorted.length - MAX_SHOWN} more.`));\n }\n\n lines.push(\"\");\n if (inv.hndlCount > 0) {\n lines.push(\n c(\n ANSI.yellow,\n `Note: ${inv.hndlCount} finding(s) are exposed to \"harvest now, decrypt later\" — ` +\n \"encrypted traffic captured today can be decrypted once a quantum computer exists. \" +\n \"Prioritise migrating key exchange / encryption to hybrid PQC (X25519MLKEM768).\",\n ),\n );\n }\n\n if (options?.tier) {\n lines.push(\"\", ...formatTierGuidance(inv.byAlgorithm, options.tier));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Per-family migration targets for a CNSA security tier — surfaces the otherwise\n * library-only {@link remediationForTier} in human reports. Category 5 shows the\n * ML-KEM-1024 / ML-DSA-87 sets CNSA 2.0 mandates for national-security systems and\n * long-lived secrets. Returns plain (un-coloured) lines; the caller styles them.\n */\nexport function formatTierGuidance(\n byAlgorithm: Record<string, number>,\n tier: SecurityTier,\n): string[] {\n const label = tier === \"category-5\" ? \"CNSA 2.0 (Category 5)\" : \"Category 3 (commercial)\";\n const out: string[] = [`${label} migration targets:`];\n const seen = new Set<string>();\n for (const [k, n] of Object.entries(byAlgorithm)) {\n if (n <= 0) continue;\n const fam = k as AlgorithmFamily;\n if (fam === \"unknown\" || !remediationFor(fam)) continue; // skip unmapped families\n const rem = remediationForTier(fam, tier);\n if (seen.has(rem.recommendation)) continue;\n seen.add(rem.recommendation);\n out.push(` ${fam} → ${rem.recommendation}`);\n }\n if (tier === \"category-5\") {\n out.push(\n \" CNSA 2.0 mandates ML-KEM-1024 / ML-DSA-87 for national-security systems and long-lived secrets (2030/2033 milestones).\",\n );\n }\n return out;\n}\n"]}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reporters: turn a {@link ScanResult} into SARIF 2.1.0, a clean JSON object,\n * or a human-readable text summary. No third-party dependencies — ANSI colour\n * is emitted with raw escape codes and is off by default.\n */\nimport type { AlgorithmFamily, Finding, RuleMeta, ScanResult, Severity } from \"./types.js\";\nimport { VERSION } from \"./version.js\";\nimport { SEVERITY_ORDER, sarifLevel } from \"./severity.js\";\nimport { ANALYZABLE_LANGUAGES_LABEL } from \"./detect-utils.js\";\nimport { remediationFor, remediationForTier, remediationForProfile } from \"./remediation.js\";\nimport type { SecurityTier } from \"./remediation.js\";\nimport type { StandardsProfile } from \"./standards-profiles.js\";\nimport { fingerprintFinding } from \"./baseline.js\";\n\n/** Minimal SARIF 2.1.0 log shape (kept permissive on purpose). */\nexport interface SarifLog {\n $schema: string;\n version: \"2.1.0\";\n runs: unknown[];\n}\n\n/** Options shared by the structured reporters ({@link toSarif} / {@link toJson}). */\nexport interface ReportOptions {\n /**\n * Omit `location.snippet` from every finding in the output. Defaults to false\n * (snippets are included). Snippets of `sensitive` findings (e.g. PEM key\n * blocks, SSH public keys) are ALWAYS omitted regardless of this flag — the\n * snippet there IS the sensitive value.\n */\n redactSnippets?: boolean;\n /**\n * Full rule catalog to advertise in SARIF `tool.driver.rules[]`, even for\n * rules that produced no finding in this run. Pass\n * `defaultRegistry.ruleCatalog()`. When omitted, only the rules that actually\n * fired are emitted (the historical behaviour). SARIF-only; ignored by\n * {@link toJson}.\n */\n catalog?: RuleMeta[];\n}\n\nconst SARIF_SCHEMA =\n \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\";\n\nconst INFORMATION_URI = \"https://github.com/quantakrypto/pqc-tools\";\n\n/**\n * Resolve the snippet to emit for a finding, honouring redaction. Sensitive\n * findings (key material) never expose their snippet; otherwise the snippet is\n * dropped only when `redactSnippets` is set.\n */\nfunction emittedSnippet(f: Finding, redactSnippets: boolean): string | undefined {\n if (redactSnippets || f.sensitive) return undefined;\n return f.location.snippet;\n}\n\n/** Map our severity to a SARIF rule-level default (used in rules[].defaultConfiguration). */\nfunction sarifRank(severity: Severity): number {\n switch (severity) {\n case \"critical\":\n return 100;\n case \"high\":\n return 80;\n case \"medium\":\n return 50;\n case \"low\":\n return 20;\n default:\n return 5;\n }\n}\n\n/** Build a SARIF `rules[]` entry from a rule's severity/title/message/etc. */\nfunction sarifRule(spec: {\n id: string;\n title: string;\n message: string;\n severity: Severity;\n category: string;\n algorithm?: string;\n hndl: boolean;\n cwe?: string;\n remediation?: string;\n}): Record<string, unknown> {\n return {\n id: spec.id,\n name: spec.id,\n shortDescription: { text: spec.title },\n fullDescription: { text: spec.message },\n defaultConfiguration: { level: sarifLevel(spec.severity), rank: sarifRank(spec.severity) },\n ...(spec.remediation ? { help: { text: `Remediation: ${spec.remediation}` } } : {}),\n properties: {\n category: spec.category,\n ...(spec.algorithm ? { algorithm: spec.algorithm } : {}),\n hndl: spec.hndl,\n ...(spec.cwe ? { cwe: spec.cwe, \"security-severity\": securitySeverity(spec.severity) } : {}),\n ...(spec.cwe ? { tags: [\"security\", spec.cwe] } : {}),\n },\n ...(spec.cwe\n ? {\n relationships: [\n { target: { id: spec.cwe, toolComponent: { name: \"CWE\" } }, kinds: [\"relevant\"] },\n ],\n }\n : {}),\n };\n}\n\n/** Serialize a scan result as SARIF 2.1.0. */\nexport function toSarif(result: ScanResult, opts?: ReportOptions): SarifLog {\n const redactSnippets = opts?.redactSnippets ?? false;\n // Build the rule set and collect the CWE taxa referenced by any rule. When a\n // full catalog is supplied, advertise every rule (even ones that didn't fire);\n // otherwise emit one rule per ruleId encountered (the historical behaviour).\n const ruleIndex = new Map<string, number>();\n const rules: Array<Record<string, unknown>> = [];\n const cweTaxa = new Set<string>();\n\n for (const r of opts?.catalog ?? []) {\n if (ruleIndex.has(r.id)) continue;\n if (r.cwe) cweTaxa.add(r.cwe);\n ruleIndex.set(r.id, rules.length);\n rules.push(\n sarifRule({\n id: r.id,\n title: r.title,\n message: r.message,\n severity: r.severity,\n category: r.category,\n algorithm: r.algorithm,\n hndl: r.hndl,\n cwe: r.cwe,\n remediation: r.remediation,\n }),\n );\n }\n\n for (const f of result.findings) {\n if (f.cwe) cweTaxa.add(f.cwe);\n if (ruleIndex.has(f.ruleId)) continue;\n ruleIndex.set(f.ruleId, rules.length);\n rules.push(\n sarifRule({\n id: f.ruleId,\n title: f.title,\n message: f.message,\n severity: f.severity,\n category: f.category,\n algorithm: f.algorithm,\n hndl: f.hndl,\n cwe: f.cwe,\n remediation: f.remediation,\n }),\n );\n }\n\n const results = result.findings.map((f) => {\n const region: Record<string, number> = { startLine: f.location.line };\n if (typeof f.location.column === \"number\") region.startColumn = f.location.column;\n if (typeof f.location.endLine === \"number\") region.endLine = f.location.endLine;\n const snippet = emittedSnippet(f, redactSnippets);\n\n return {\n ruleId: f.ruleId,\n ruleIndex: ruleIndex.get(f.ruleId),\n level: sarifLevel(f.severity),\n message: { text: f.message },\n // Line-INSENSITIVE fingerprint (the same one the baseline uses:\n // sha256 of ruleId|file|normalizedSnippet). GitHub code scanning keys\n // alert identity + dedup off partialFingerprints, so a finding survives\n // line shifts and reformatting instead of re-alerting as \"new\" on every\n // edit above it. `quantakrypto/v1` names our scheme.\n partialFingerprints: { \"quantakrypto/v1\": fingerprintFinding(f) },\n properties: {\n category: f.category,\n severity: f.severity,\n confidence: f.confidence,\n hndl: f.hndl,\n ...(f.algorithm ? { algorithm: f.algorithm } : {}),\n ...(f.remediation ? { remediation: f.remediation } : {}),\n ...(f.cwe ? { cwe: f.cwe } : {}),\n },\n ...(f.cwe\n ? {\n taxa: [\n {\n target: { id: f.cwe, toolComponent: { name: \"CWE\" } },\n },\n ],\n }\n : {}),\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: f.location.file },\n region: {\n ...region,\n ...(snippet ? { snippet: { text: snippet } } : {}),\n },\n },\n },\n ],\n };\n });\n\n // CWE taxonomy component (SARIF taxonomies), referenced by rules + results.\n const taxonomies =\n cweTaxa.size > 0\n ? [\n {\n name: \"CWE\",\n informationUri: \"https://cwe.mitre.org/\",\n organization: \"MITRE\",\n shortDescription: { text: \"The MITRE Common Weakness Enumeration\" },\n taxa: [...cweTaxa].sort().map((id) => ({\n id,\n helpUri: `https://cwe.mitre.org/data/definitions/${id.replace(/^CWE-/, \"\")}.html`,\n })),\n },\n ]\n : [];\n\n return {\n $schema: SARIF_SCHEMA,\n version: \"2.1.0\",\n runs: [\n {\n tool: {\n driver: {\n name: \"qScan\",\n informationUri: INFORMATION_URI,\n version: result.toolVersion || VERSION,\n rules,\n },\n },\n ...(taxonomies.length > 0 ? { taxonomies } : {}),\n results,\n },\n ],\n };\n}\n\n/** GitHub-code-scanning `security-severity` (0–10) derived from our severity. */\nfunction securitySeverity(severity: Severity): string {\n switch (severity) {\n case \"critical\":\n return \"9.5\";\n case \"high\":\n return \"8.0\";\n case \"medium\":\n return \"5.0\";\n case \"low\":\n return \"3.0\";\n default:\n return \"1.0\";\n }\n}\n\n/** Serialize a scan result as a plain JSON-friendly object. */\nexport function toJson(result: ScanResult, opts?: ReportOptions): Record<string, unknown> {\n const redactSnippets = opts?.redactSnippets ?? false;\n return {\n toolVersion: result.toolVersion,\n root: result.root,\n startedAt: result.startedAt,\n finishedAt: result.finishedAt,\n filesScanned: result.filesScanned,\n ...(result.analyzedFiles !== undefined ? { analyzedFiles: result.analyzedFiles } : {}),\n ...(result.diagnostics ? { diagnostics: result.diagnostics } : {}),\n inventory: {\n readinessScore: result.inventory.readinessScore,\n hndlCount: result.inventory.hndlCount,\n bySeverity: result.inventory.bySeverity,\n byCategory: result.inventory.byCategory,\n byAlgorithm: result.inventory.byAlgorithm,\n },\n findings: result.findings.map((f) => ({\n ruleId: f.ruleId,\n title: f.title,\n category: f.category,\n severity: f.severity,\n confidence: f.confidence,\n algorithm: f.algorithm,\n hndl: f.hndl,\n message: f.message,\n remediation: f.remediation,\n cwe: f.cwe,\n location: {\n file: f.location.file,\n line: f.location.line,\n column: f.location.column,\n endLine: f.location.endLine,\n snippet: emittedSnippet(f, redactSnippets),\n },\n })),\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Human-readable summary */\n/* -------------------------------------------------------------------------- */\n\n/** Raw ANSI codes (no chalk). Disabled when colour is off. */\nconst ANSI = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n} as const;\n\nfunction severityColor(sev: Severity): string {\n switch (sev) {\n case \"critical\":\n return ANSI.magenta;\n case \"high\":\n return ANSI.red;\n case \"medium\":\n return ANSI.yellow;\n case \"low\":\n return ANSI.blue;\n default:\n return ANSI.dim;\n }\n}\n\nfunction scoreColor(score: number): string {\n if (score >= 80) return ANSI.green;\n if (score >= 50) return ANSI.yellow;\n return ANSI.red;\n}\n\n/**\n * Render a human-readable summary of a scan result. Colour is off by default;\n * pass `{ color: true }` to emit ANSI escape codes.\n */\nexport function formatSummary(\n result: ScanResult,\n options?: { color?: boolean; tier?: SecurityTier },\n): string {\n const color = options?.color ?? false;\n const c = (code: string, text: string): string => (color ? `${code}${text}${ANSI.reset}` : text);\n\n const lines: string[] = [];\n const inv = result.inventory;\n\n lines.push(c(ANSI.bold, \"qScan — post-quantum readiness report\"));\n lines.push(c(ANSI.dim, `tool v${result.toolVersion} · root: ${result.root}`));\n lines.push(\"\");\n\n // Readiness score banner.\n lines.push(\n `Readiness score: ${c(`${ANSI.bold}${scoreColor(inv.readinessScore)}`, `${inv.readinessScore}/100`)}`,\n );\n const analyzed =\n result.analyzedFiles !== undefined\n ? ` Analyzed (${ANALYZABLE_LANGUAGES_LABEL}): ${result.analyzedFiles}`\n : \"\";\n lines.push(\n `Files scanned: ${result.filesScanned}${analyzed} Findings: ${result.findings.length} HNDL-exposed: ${c(\n inv.hndlCount > 0 ? ANSI.red : ANSI.green,\n String(inv.hndlCount),\n )}`,\n );\n // Coverage honesty: a score over zero analyzable files is not a clean bill of health.\n if (result.analyzedFiles === 0 && result.filesScanned > 0) {\n lines.push(\n c(\n ANSI.yellow,\n `Note: 0 files were in a supported source language (${ANALYZABLE_LANGUAGES_LABEL}) — the readiness score does not reflect this codebase.`,\n ),\n );\n }\n // Coverage diagnostics: skipped files mean the finding count may be incomplete.\n const diag = result.diagnostics;\n if (diag && (diag.unreadable > 0 || diag.skippedMinified > 0)) {\n lines.push(\n c(\n ANSI.yellow,\n `Coverage: ${diag.unreadable} unreadable, ${diag.skippedMinified} skipped as minified — results may be incomplete.`,\n ),\n );\n }\n lines.push(\"\");\n\n // Severity breakdown.\n const sevParts = SEVERITY_ORDER.filter((s) => inv.bySeverity[s] > 0).map((s) =>\n c(severityColor(s), `${s}: ${inv.bySeverity[s]}`),\n );\n lines.push(`By severity: ${sevParts.length ? sevParts.join(\" \") : c(ANSI.green, \"none\")}`);\n\n // Algorithm breakdown.\n const algoParts = Object.entries(inv.byAlgorithm)\n .sort((a, b) => b[1] - a[1])\n .map(([k, v]) => `${k}: ${v}`);\n if (algoParts.length) lines.push(`By algorithm: ${algoParts.join(\" \")}`);\n lines.push(\"\");\n\n if (result.findings.length === 0) {\n lines.push(c(ANSI.green, \"No classical asymmetric cryptography detected. ✓\"));\n return lines.join(\"\\n\");\n }\n\n // Top findings, grouped by severity (most severe first), capped for readability.\n const sorted = [...result.findings].sort(\n (a, b) => SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity),\n );\n const MAX_SHOWN = 25;\n lines.push(\n c(ANSI.bold, `Top findings (${Math.min(MAX_SHOWN, sorted.length)} of ${sorted.length}):`),\n );\n\n for (const f of sorted.slice(0, MAX_SHOWN)) {\n const loc = `${f.location.file}:${f.location.line}${\n f.location.column ? `:${f.location.column}` : \"\"\n }`;\n const tag = c(severityColor(f.severity), `[${f.severity}]`);\n const hndl = f.hndl ? c(ANSI.red, \" (HNDL)\") : \"\";\n lines.push(` ${tag} ${f.title}${hndl}`);\n lines.push(c(ANSI.dim, ` ${loc} — ${f.message}`));\n if (f.remediation) lines.push(c(ANSI.cyan, ` → ${f.remediation}`));\n }\n\n if (sorted.length > MAX_SHOWN) {\n lines.push(c(ANSI.dim, ` …and ${sorted.length - MAX_SHOWN} more.`));\n }\n\n lines.push(\"\");\n if (inv.hndlCount > 0) {\n lines.push(\n c(\n ANSI.yellow,\n `Note: ${inv.hndlCount} finding(s) are exposed to \"harvest now, decrypt later\" — ` +\n \"encrypted traffic captured today can be decrypted once a quantum computer exists. \" +\n \"Prioritise migrating key exchange / encryption to hybrid PQC (X25519MLKEM768).\",\n ),\n );\n }\n\n if (options?.tier) {\n lines.push(\"\", ...formatTierGuidance(inv.byAlgorithm, options.tier));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Per-family migration targets for a CNSA security tier — surfaces the otherwise\n * library-only {@link remediationForTier} in human reports. Category 5 shows the\n * ML-KEM-1024 / ML-DSA-87 sets CNSA 2.0 mandates for national-security systems and\n * long-lived secrets. Returns plain (un-coloured) lines; the caller styles them.\n */\nexport function formatTierGuidance(\n byAlgorithm: Record<string, number>,\n tier: SecurityTier,\n): string[] {\n const label = tier === \"category-5\" ? \"CNSA 2.0 (Category 5)\" : \"Category 3 (commercial)\";\n const out: string[] = [`${label} migration targets:`];\n const seen = new Set<string>();\n for (const [k, n] of Object.entries(byAlgorithm)) {\n if (n <= 0) continue;\n const fam = k as AlgorithmFamily;\n if (fam === \"unknown\" || !remediationFor(fam)) continue; // skip unmapped families\n const rem = remediationForTier(fam, tier);\n if (seen.has(rem.recommendation)) continue;\n seen.add(rem.recommendation);\n out.push(` ${fam} → ${rem.recommendation}`);\n }\n if (tier === \"category-5\") {\n out.push(\n \" CNSA 2.0 mandates ML-KEM-1024 / ML-DSA-87 for national-security systems and long-lived secrets (2030/2033 milestones).\",\n );\n }\n return out;\n}\n\n/**\n * Per-family migration targets tailored to a selected {@link StandardsProfile}\n * (`--profile`). Unlike {@link formatTierGuidance} (CNSA-tier only), this surfaces the\n * regime's parameter sets AND its hybrid stance — required (ANSSI/BSI) vs recommended\n * (NIST/NCSC) vs optional (CNSA 2.0) — so guidance isn't regime-wrong. Returns plain\n * (un-coloured) lines; the caller styles them.\n */\nexport function formatProfileGuidance(\n byAlgorithm: Record<string, number>,\n profile: StandardsProfile,\n): string[] {\n const out: string[] = [`${profile.name} migration targets:`];\n const seen = new Set<string>();\n for (const [k, n] of Object.entries(byAlgorithm)) {\n if (n <= 0) continue;\n const fam = k as AlgorithmFamily;\n if (fam === \"unknown\" || !remediationFor(fam)) continue; // skip unmapped families\n const rem = remediationForProfile(fam, profile);\n if (seen.has(rem.recommendation)) continue;\n seen.add(rem.recommendation);\n out.push(` ${fam} → ${rem.recommendation}`);\n }\n const stance =\n profile.hybridStance === \"required\"\n ? \"requires classical+PQC hybridization\"\n : profile.hybridStance === \"recommended\"\n ? \"recommends hybridization\"\n : \"does not require hybridization\";\n out.push(\n ` ${profile.authority} ${stance}; classical public-key crypto disallowed after ${profile.disallowAfter} (${profile.citation}).`,\n );\n return out;\n}\n"]}
@@ -13,7 +13,7 @@ import * as path from "node:path";
13
13
  import { parentPort, workerData } from "node:worker_threads";
14
14
  import { defaultRegistry } from "./registry.js";
15
15
  import { detectFile } from "./scan.js";
16
- import { looksMinified } from "./walk.js";
16
+ import { isKeystorePath, looksMinified } from "./walk.js";
17
17
  import { isManifestFile } from "./dependencies.js";
18
18
  if (parentPort) {
19
19
  const data = (workerData ?? {});
@@ -30,15 +30,17 @@ if (parentPort) {
30
30
  const scannedNames = [];
31
31
  for (const rel of req.files) {
32
32
  const abs = path.join(baseDir, ...rel.split("/"));
33
+ // Keystores (.jks/.p12/…) are read byte-preserving (latin1); see scan.ts.
34
+ const keystore = isKeystorePath(rel);
33
35
  let content;
34
36
  try {
35
- content = readFileSync(abs, "utf8");
37
+ content = readFileSync(abs, keystore ? "latin1" : "utf8");
36
38
  }
37
39
  catch {
38
40
  unreadable += 1;
39
41
  continue;
40
42
  }
41
- if (!toggles.scanMinified && !isManifestFile(rel) && looksMinified(content)) {
43
+ if (!toggles.scanMinified && !isManifestFile(rel) && !keystore && looksMinified(content)) {
42
44
  skippedMinified += 1;
43
45
  continue;
44
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scan-worker.js","sourceRoot":"","sources":["../src/scan-worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAG7D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAenD,IAAI,UAAU,EAAE,CAAC;IACf,MAAM,IAAI,GAAG,CAAC,UAAU,IAAI,EAAE,CAAgD,CAAC;IAC/E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,UAAU,CAAC;IAExB,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAiB,EAAE,EAAE;QACvC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAc,EAAE,CAAC;YAC/B,IAAI,YAAY,GAAG,CAAC,CAAC;YACrB,IAAI,UAAU,GAAG,CAAC,CAAC;YACnB,IAAI,eAAe,GAAG,CAAC,CAAC;YACxB,MAAM,YAAY,GAAa,EAAE,CAAC;YAElC,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;gBAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;gBAClD,IAAI,OAAe,CAAC;gBACpB,IAAI,CAAC;oBACH,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBACtC,CAAC;gBAAC,MAAM,CAAC;oBACP,UAAU,IAAI,CAAC,CAAC;oBAChB,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC5E,eAAe,IAAI,CAAC,CAAC;oBACrB,SAAS;gBACX,CAAC;gBACD,YAAY,IAAI,CAAC,CAAC;gBAClB,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACvB,QAAQ,CAAC,IAAI,CACX,GAAG,UAAU,CACX,GAAG,EACH,OAAO,EACP,IAAI,EACJ;oBACE,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,IAAI,EAAE,OAAO,CAAC,IAAI;iBACnB,EACD,OAAO,CAAC,aAAa,CACtB,CACF,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,WAAW,CAAC;gBACf,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,KAAK,EAAE,YAAY;gBACnB,MAAM,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE;aAChE,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,WAAW,CAAC;gBACf,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Worker-thread entry for {@link scanParallel}. Built to `dist/scan-worker.js`\n * and spawned by `parallel.ts`. Each worker reads its assigned files and runs\n * the SAME pure detector pipeline as the serial scan (`detectFile`), returning\n * `{ findings, filesScanned }` per chunk. No shared mutable state.\n *\n * This file performs side effects (wires up message handlers) only when it is\n * actually running inside a worker thread, so importing it from the main thread\n * (e.g. for coverage) is harmless.\n */\nimport { readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport { parentPort, workerData } from \"node:worker_threads\";\n\nimport type { Finding } from \"./types.js\";\nimport { defaultRegistry } from \"./registry.js\";\nimport { detectFile } from \"./scan.js\";\nimport { looksMinified } from \"./walk.js\";\nimport { isManifestFile } from \"./dependencies.js\";\n\ninterface WorkerToggles {\n source: boolean;\n config: boolean;\n deps: boolean;\n scanMinified: boolean;\n disabledRules?: string[];\n}\n\ninterface ChunkRequest {\n index: number;\n files: string[];\n}\n\nif (parentPort) {\n const data = (workerData ?? {}) as { baseDir: string; toggles: WorkerToggles };\n const baseDir = data.baseDir;\n const toggles = data.toggles;\n const dets = defaultRegistry.all();\n const port = parentPort;\n\n port.on(\"message\", (req: ChunkRequest) => {\n try {\n const findings: Finding[] = [];\n let filesScanned = 0;\n let unreadable = 0;\n let skippedMinified = 0;\n const scannedNames: string[] = [];\n\n for (const rel of req.files) {\n const abs = path.join(baseDir, ...rel.split(\"/\"));\n let content: string;\n try {\n content = readFileSync(abs, \"utf8\");\n } catch {\n unreadable += 1;\n continue;\n }\n if (!toggles.scanMinified && !isManifestFile(rel) && looksMinified(content)) {\n skippedMinified += 1;\n continue;\n }\n filesScanned += 1;\n scannedNames.push(rel);\n findings.push(\n ...detectFile(\n rel,\n content,\n dets,\n {\n source: toggles.source,\n config: toggles.config,\n deps: toggles.deps,\n },\n toggles.disabledRules,\n ),\n );\n }\n\n port.postMessage({\n index: req.index,\n files: scannedNames,\n result: { findings, filesScanned, unreadable, skippedMinified },\n });\n } catch (err) {\n port.postMessage({\n index: req.index,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n });\n}\n"]}
1
+ {"version":3,"file":"scan-worker.js","sourceRoot":"","sources":["../src/scan-worker.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Worker-thread entry for {@link scanParallel}. Built to `dist/scan-worker.js`\n * and spawned by `parallel.ts`. Each worker reads its assigned files and runs\n * the SAME pure detector pipeline as the serial scan (`detectFile`), returning\n * `{ findings, filesScanned }` per chunk. No shared mutable state.\n *\n * This file performs side effects (wires up message handlers) only when it is\n * actually running inside a worker thread, so importing it from the main thread\n * (e.g. for coverage) is harmless.\n */\nimport { readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport { parentPort, workerData } from \"node:worker_threads\";\n\nimport type { Finding } from \"./types.js\";\nimport { defaultRegistry } from \"./registry.js\";\nimport { detectFile } from \"./scan.js\";\nimport { isKeystorePath, looksMinified } from \"./walk.js\";\nimport { isManifestFile } from \"./dependencies.js\";\n\ninterface WorkerToggles {\n source: boolean;\n config: boolean;\n deps: boolean;\n scanMinified: boolean;\n disabledRules?: string[];\n}\n\ninterface ChunkRequest {\n index: number;\n files: string[];\n}\n\nif (parentPort) {\n const data = (workerData ?? {}) as { baseDir: string; toggles: WorkerToggles };\n const baseDir = data.baseDir;\n const toggles = data.toggles;\n const dets = defaultRegistry.all();\n const port = parentPort;\n\n port.on(\"message\", (req: ChunkRequest) => {\n try {\n const findings: Finding[] = [];\n let filesScanned = 0;\n let unreadable = 0;\n let skippedMinified = 0;\n const scannedNames: string[] = [];\n\n for (const rel of req.files) {\n const abs = path.join(baseDir, ...rel.split(\"/\"));\n // Keystores (.jks/.p12/…) are read byte-preserving (latin1); see scan.ts.\n const keystore = isKeystorePath(rel);\n let content: string;\n try {\n content = readFileSync(abs, keystore ? \"latin1\" : \"utf8\");\n } catch {\n unreadable += 1;\n continue;\n }\n if (!toggles.scanMinified && !isManifestFile(rel) && !keystore && looksMinified(content)) {\n skippedMinified += 1;\n continue;\n }\n filesScanned += 1;\n scannedNames.push(rel);\n findings.push(\n ...detectFile(\n rel,\n content,\n dets,\n {\n source: toggles.source,\n config: toggles.config,\n deps: toggles.deps,\n },\n toggles.disabledRules,\n ),\n );\n }\n\n port.postMessage({\n index: req.index,\n files: scannedNames,\n result: { findings, filesScanned, unreadable, skippedMinified },\n });\n } catch (err) {\n port.postMessage({\n index: req.index,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAuB7E;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,EAAE,QAAQ,EAAqB,CAAC;AAEtD,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAI9D;AAOD;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,EAC5D,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAChC,OAAO,EAAE,CA8BX;AAED;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA0IpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,SAAS,CAAC,GAChD,MAAM,EAAE,CAmBV"}
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAwC7E;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,EAAE,QAAQ,EAAqB,CAAC;AAEtD,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAI9D;AAOD;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,EAC5D,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAChC,OAAO,EAAE,CA8BX;AAED;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA4JpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,SAAS,CAAC,GAChD,MAAM,EAAE,CAmBV"}
package/dist/scan.js CHANGED
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import { readFile, stat } from "node:fs/promises";
13
13
  import * as path from "node:path";
14
- import { walkFiles, toPosix, isBinaryPath, looksMinified, matchesAny } from "./walk.js";
14
+ import { walkFiles, toPosix, isBinaryPath, isKeystorePath, looksMinified, matchesAny, DEFAULT_MAX_FILE_SIZE, } from "./walk.js";
15
15
  import { isAnalyzableSource } from "./detect-utils.js";
16
16
  import { stripCommentFindings, stripIgnoredFindings, stripStringLiteralFindings, } from "./comments.js";
17
17
  /**
@@ -19,7 +19,16 @@ import { stripCommentFindings, stripIgnoredFindings, stripStringLiteralFindings,
19
19
  * A match inside a string (e.g. `t.Error("SigningMethodPS256 …")`) is prose and
20
20
  * is dropped. Rules that legitimately match quoted tokens are NOT listed here.
21
21
  */
22
- const CODE_ONLY_RULES = new Set(["go-jwt-signingmethod"]);
22
+ const CODE_ONLY_RULES = new Set([
23
+ "go-jwt-signingmethod",
24
+ // Identifier-form JWT alg constants (jjwt `SignatureAlgorithm.RS256`, auth0
25
+ // `Algorithm.RSA256`, C# `SecurityAlgorithms.*`, Rust `Algorithm::RS256`). Like the
26
+ // Go rule, these are only meaningful as code; the SAME token inside a string literal
27
+ // (an error message that names/forbids the alg) is prose, not a usage.
28
+ "java-jwt-alg",
29
+ "csharp-jwt-alg",
30
+ "rust-jwt-algorithm",
31
+ ]);
23
32
  import { hashContent, loadCache, rulesetFingerprint, saveCache } from "./cache.js";
24
33
  import { builtinDetectors, defaultRegistry, detectorScope } from "./registry.js";
25
34
  import { isManifestFile, scanManifest } from "./dependencies.js";
@@ -139,22 +148,42 @@ export async function scan(options) {
139
148
  const absPath = singleFileName ? options.root : path.join(baseDir, ...rel.split("/"));
140
149
  const reportedPath = singleFileName ? toPosix(rel) : rel;
141
150
  options.onFile?.(reportedPath);
151
+ // Cryptographic keystores (.jks/.p12/…) are binary; read them byte-preserving
152
+ // (latin1) so the keystore detector can inspect magic bytes.
153
+ const keystore = isKeystorePath(reportedPath);
154
+ // Keystores are read whole into memory as latin1. The walker already caps file
155
+ // size, but the explicit-file-list (incremental) path does not — so stat and
156
+ // skip an oversized binary here to avoid reading a huge encrypted archive
157
+ // (`.gpg`) into a string.
158
+ if (keystore) {
159
+ try {
160
+ const { size } = await stat(absPath);
161
+ if (size > (options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE))
162
+ continue;
163
+ }
164
+ catch {
165
+ unreadable += 1;
166
+ continue;
167
+ }
168
+ }
142
169
  let content;
143
170
  try {
144
- content = await readFile(absPath, "utf8");
171
+ content = await readFile(absPath, keystore ? "latin1" : "utf8");
145
172
  }
146
173
  catch {
147
174
  unreadable += 1; // permissions / vanished / decode failure — tracked, not silent.
148
175
  continue;
149
176
  }
150
177
  // Skip machine-minified / generated content (unless explicitly enabled).
151
- // Manifests are always scanned (their findings are dependency findings).
152
- if (!scanMinified && !isManifestFile(reportedPath) && looksMinified(content)) {
178
+ // Manifests and keystores are always scanned.
179
+ if (!scanMinified && !isManifestFile(reportedPath) && !keystore && looksMinified(content)) {
153
180
  skippedMinified += 1;
154
181
  continue;
155
182
  }
156
183
  // Cumulative-byte budget: enforced once this file's bytes are accounted for.
157
- bytesScanned += Buffer.byteLength(content, "utf8");
184
+ // Use the read encoding so a latin1 keystore is counted at its on-disk size
185
+ // (a utf8 byteLength would double-count every byte ≥ 0x80).
186
+ bytesScanned += Buffer.byteLength(content, keystore ? "latin1" : "utf8");
158
187
  if (typeof maxBytes === "number" && bytesScanned > maxBytes) {
159
188
  throw new BudgetExceededError(`maxBytes budget exceeded (limit: ${maxBytes}).`);
160
189
  }
package/dist/scan.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Scan orchestrator. Walks the target (or an explicit file list), runs the\n * applicable detectors over each file, parses dependency manifests, aggregates\n * everything into an inventory, and returns a {@link ScanResult} with timing and\n * the tool version.\n *\n * Detector scope (source vs config) is driven by each {@link Detector}'s\n * declared `scope` (defaulting to \"source\"), not by ruleId prefixes. The\n * detector set comes from {@link defaultRegistry} unless overridden via\n * `options.detectors`.\n */\nimport { readFile, stat } from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nimport type { Detector, Finding, ScanOptions, ScanResult } from \"./types.js\";\nimport { walkFiles, toPosix, isBinaryPath, looksMinified, matchesAny } from \"./walk.js\";\nimport { isAnalyzableSource } from \"./detect-utils.js\";\nimport {\n stripCommentFindings,\n stripIgnoredFindings,\n stripStringLiteralFindings,\n} from \"./comments.js\";\n\n/**\n * Rules whose token is only meaningful as code, never inside a string literal.\n * A match inside a string (e.g. `t.Error(\"SigningMethodPS256 …\")`) is prose and\n * is dropped. Rules that legitimately match quoted tokens are NOT listed here.\n */\nconst CODE_ONLY_RULES: ReadonlySet<string> = new Set([\"go-jwt-signingmethod\"]);\nimport { hashContent, loadCache, rulesetFingerprint, saveCache } from \"./cache.js\";\nimport type { CacheEntry } from \"./cache.js\";\nimport { builtinDetectors, defaultRegistry, detectorScope } from \"./registry.js\";\nimport { isManifestFile, scanManifest } from \"./dependencies.js\";\nimport { buildInventory } from \"./inventory.js\";\nimport { AbortError, BudgetExceededError } from \"./errors.js\";\nimport { VERSION } from \"./version.js\";\n\n/**\n * The full set of built-in detectors exposed on the public API. Re-exported\n * from {@link builtinDetectors} in `registry.ts` — the single source of truth\n * the {@link defaultRegistry} is also built from — so the public array and the\n * registry can never drift apart. The manifest scanner is handled separately\n * (it parses JSON rather than running a Detector).\n */\nexport const detectors: Detector[] = builtinDetectors;\n\n/** Stable comparator: by file, then line, then ruleId. Exported for reuse. */\nexport function compareFindings(a: Finding, b: Finding): number {\n if (a.location.file !== b.location.file) return a.location.file < b.location.file ? -1 : 1;\n if (a.location.line !== b.location.line) return a.location.line - b.location.line;\n return a.ruleId < b.ruleId ? -1 : a.ruleId > b.ruleId ? 1 : 0;\n}\n\n/** Resolve the active detector list for a scan (override or the default registry). */\nfunction resolveDetectors(options: ScanOptions): Detector[] {\n return options.detectors ?? defaultRegistry.all();\n}\n\n/**\n * Run all applicable detectors + the manifest scanner over a single file's\n * contents, honouring the source / config / dependencies toggles. Pure: no I/O.\n * Exported so the parallel worker and unit tests can drive it directly.\n */\nexport function detectFile(\n file: string,\n content: string,\n dets: readonly Detector[],\n toggles: { source: boolean; config: boolean; deps: boolean },\n disabledRules?: readonly string[],\n): Finding[] {\n let out: Finding[] = [];\n\n for (const det of dets) {\n if (!det.appliesTo(file)) continue;\n const isConfig = detectorScope(det) === \"config\";\n if (isConfig ? !toggles.config : !toggles.source) continue;\n out.push(...det.detect({ file, content }));\n }\n\n // Drop lexical false positives that land inside comments (`// migrated off\n // createECDH()`), then honour inline `// qscan-ignore-line` /\n // `qscan-ignore-next-line` directives. Both run before the dependency scan\n // appends its findings (manifests carry neither).\n out = stripCommentFindings(out, content, file);\n out = stripStringLiteralFindings(out, content, file, CODE_ONLY_RULES);\n out = stripIgnoredFindings(out, content);\n\n if (toggles.deps && isManifestFile(file)) {\n out.push(...scanManifest(file, content));\n }\n\n // Per-rule suppression: drop findings whose ruleId was disabled. Applied here\n // so both the serial scan and the worker path honour it identically.\n if (disabledRules && disabledRules.length > 0) {\n const disabled = new Set(disabledRules);\n return out.filter((f) => !disabled.has(f.ruleId));\n }\n\n return out;\n}\n\n/**\n * Recursively scan a directory (or single file, or explicit file list) for\n * classical asymmetric crypto. Honours the source / dependencies / config\n * toggles (all default true) and reports progress through `options.onFile`.\n */\nexport async function scan(options: ScanOptions): Promise<ScanResult> {\n const startedAt = new Date();\n\n const doSource = options.source !== false;\n const doDeps = options.dependencies !== false;\n const doConfig = options.config !== false;\n const scanMinified = options.scanMinified === true;\n const dets = resolveDetectors(options);\n\n // Resolve whether the root is a file so we can rebuild absolute paths to read.\n const rootStat = await stat(options.root);\n const rootIsFile = rootStat.isFile();\n const baseDir = rootIsFile ? path.dirname(options.root) : options.root;\n const singleFileName = rootIsFile ? path.basename(options.root) : null;\n\n const findings: Finding[] = [];\n let filesScanned = 0;\n let analyzedFiles = 0;\n let bytesScanned = 0;\n let unreadable = 0;\n let skippedMinified = 0;\n\n // Optional content-hash scan cache: unchanged files reuse prior findings.\n const cacheFile = options.cacheFile;\n const ruleset = cacheFile ? rulesetFingerprint(dets, options.disabledRules) : \"\";\n const cache = cacheFile ? await loadCache(cacheFile, ruleset) : null;\n // A full scan starts with an empty next-cache so files that vanished are\n // evicted. An INCREMENTAL scan (explicit `files` list) only visits a subset,\n // so seed the next-cache with the existing entries — otherwise saving would\n // drop every file we didn't happen to scan this run (audit: arch #4).\n const incremental = Array.isArray(options.files);\n const nextEntries: Map<string, CacheEntry> | null = cacheFile\n ? new Map(incremental && cache ? cache : [])\n : null;\n\n // Work-budget / cancellation controls (all optional, unlimited when omitted).\n const signal = options.signal;\n const maxFiles = options.maxFiles;\n const maxBytes = options.maxBytes;\n\n // Source of relative paths: an explicit file list (incremental) or the walker.\n const relPaths: AsyncIterable<string> = options.files\n ? filterExplicitFiles(options.files, options)\n : walkFiles(options.root, {\n include: options.include,\n exclude: options.exclude,\n noDefaultIgnores: options.noDefaultIgnores,\n maxFileSize: options.maxFileSize,\n });\n\n for await (const rel of relPaths) {\n // Cooperative cancellation: check the signal at the top of every iteration.\n if (signal?.aborted) throw new AbortError();\n\n // File-count budget: enforced before reading the next file.\n if (typeof maxFiles === \"number\" && filesScanned >= maxFiles) {\n throw new BudgetExceededError(`maxFiles budget exceeded (limit: ${maxFiles}).`);\n }\n\n // In single-file mode, walkFiles yields the basename; map back to the file.\n const absPath = singleFileName ? options.root : path.join(baseDir, ...rel.split(\"/\"));\n const reportedPath = singleFileName ? toPosix(rel) : rel;\n\n options.onFile?.(reportedPath);\n\n let content: string;\n try {\n content = await readFile(absPath, \"utf8\");\n } catch {\n unreadable += 1; // permissions / vanished / decode failure — tracked, not silent.\n continue;\n }\n\n // Skip machine-minified / generated content (unless explicitly enabled).\n // Manifests are always scanned (their findings are dependency findings).\n if (!scanMinified && !isManifestFile(reportedPath) && looksMinified(content)) {\n skippedMinified += 1;\n continue;\n }\n\n // Cumulative-byte budget: enforced once this file's bytes are accounted for.\n bytesScanned += Buffer.byteLength(content, \"utf8\");\n if (typeof maxBytes === \"number\" && bytesScanned > maxBytes) {\n throw new BudgetExceededError(`maxBytes budget exceeded (limit: ${maxBytes}).`);\n }\n\n filesScanned += 1;\n if (isAnalyzableSource(reportedPath)) analyzedFiles += 1;\n\n // Cache: reuse prior findings when the content hash matches; otherwise scan\n // and record. `nextEntries` becomes the new cache (dropping vanished files).\n let fileFindings: Finding[];\n if (cache && nextEntries) {\n const hash = hashContent(content);\n const hit = cache.get(reportedPath);\n fileFindings =\n hit && hit.hash === hash\n ? hit.findings\n : detectFile(\n reportedPath,\n content,\n dets,\n { source: doSource, config: doConfig, deps: doDeps },\n options.disabledRules,\n );\n nextEntries.set(reportedPath, { hash, findings: fileFindings });\n } else {\n fileFindings = detectFile(\n reportedPath,\n content,\n dets,\n { source: doSource, config: doConfig, deps: doDeps },\n options.disabledRules,\n );\n }\n findings.push(...fileFindings);\n }\n\n // Persist the cache (best effort) before ordering/returning.\n if (cacheFile && nextEntries) await saveCache(cacheFile, ruleset, nextEntries);\n\n // Stable ordering: by file, then line, then ruleId.\n findings.sort(compareFindings);\n\n const inventory = buildInventory(findings);\n const finishedAt = new Date();\n\n return {\n root: options.root,\n findings,\n filesScanned,\n analyzedFiles,\n diagnostics: { unreadable, skippedMinified },\n inventory,\n startedAt: startedAt.toISOString(),\n finishedAt: finishedAt.toISOString(),\n toolVersion: VERSION,\n };\n}\n\n/**\n * Filter an explicit relative file list down to the paths that pass the binary\n * filter and the include/exclude patterns, returning them deduped and sorted for\n * deterministic output. Size limits are enforced later (we still read manifests\n * over the cap). Non-existent files are simply skipped at read time.\n *\n * Pure + synchronous, and exported so the parallel enumerator applies the EXACT\n * same filtering for explicit file lists as the serial path (byte-for-byte\n * identical results under `--parallel`).\n */\nexport function filterExplicitFileList(\n files: readonly string[],\n options: Pick<ScanOptions, \"include\" | \"exclude\">,\n): string[] {\n const include = options.include ?? [];\n const exclude = options.exclude ?? [];\n const seen = new Set<string>();\n const list = [...files]\n .map((f) => toPosix(f))\n .filter((f) => {\n if (seen.has(f)) return false;\n seen.add(f);\n return true;\n })\n .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n\n return list.filter((rel) => {\n if (isBinaryPath(rel)) return false;\n if (include.length > 0 && !matchesAny(rel, include)) return false;\n if (matchesAny(rel, exclude)) return false;\n return true;\n });\n}\n\n/** Async-generator wrapper around {@link filterExplicitFileList} for `scan()`. */\nasync function* filterExplicitFiles(files: string[], options: ScanOptions): AsyncGenerator<string> {\n for (const rel of filterExplicitFileList(files, options)) yield rel;\n}\n"]}
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Scan orchestrator. Walks the target (or an explicit file list), runs the\n * applicable detectors over each file, parses dependency manifests, aggregates\n * everything into an inventory, and returns a {@link ScanResult} with timing and\n * the tool version.\n *\n * Detector scope (source vs config) is driven by each {@link Detector}'s\n * declared `scope` (defaulting to \"source\"), not by ruleId prefixes. The\n * detector set comes from {@link defaultRegistry} unless overridden via\n * `options.detectors`.\n */\nimport { readFile, stat } from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nimport type { Detector, Finding, ScanOptions, ScanResult } from \"./types.js\";\nimport {\n walkFiles,\n toPosix,\n isBinaryPath,\n isKeystorePath,\n looksMinified,\n matchesAny,\n DEFAULT_MAX_FILE_SIZE,\n} from \"./walk.js\";\nimport { isAnalyzableSource } from \"./detect-utils.js\";\nimport {\n stripCommentFindings,\n stripIgnoredFindings,\n stripStringLiteralFindings,\n} from \"./comments.js\";\n\n/**\n * Rules whose token is only meaningful as code, never inside a string literal.\n * A match inside a string (e.g. `t.Error(\"SigningMethodPS256 …\")`) is prose and\n * is dropped. Rules that legitimately match quoted tokens are NOT listed here.\n */\nconst CODE_ONLY_RULES: ReadonlySet<string> = new Set([\n \"go-jwt-signingmethod\",\n // Identifier-form JWT alg constants (jjwt `SignatureAlgorithm.RS256`, auth0\n // `Algorithm.RSA256`, C# `SecurityAlgorithms.*`, Rust `Algorithm::RS256`). Like the\n // Go rule, these are only meaningful as code; the SAME token inside a string literal\n // (an error message that names/forbids the alg) is prose, not a usage.\n \"java-jwt-alg\",\n \"csharp-jwt-alg\",\n \"rust-jwt-algorithm\",\n]);\nimport { hashContent, loadCache, rulesetFingerprint, saveCache } from \"./cache.js\";\nimport type { CacheEntry } from \"./cache.js\";\nimport { builtinDetectors, defaultRegistry, detectorScope } from \"./registry.js\";\nimport { isManifestFile, scanManifest } from \"./dependencies.js\";\nimport { buildInventory } from \"./inventory.js\";\nimport { AbortError, BudgetExceededError } from \"./errors.js\";\nimport { VERSION } from \"./version.js\";\n\n/**\n * The full set of built-in detectors exposed on the public API. Re-exported\n * from {@link builtinDetectors} in `registry.ts` — the single source of truth\n * the {@link defaultRegistry} is also built from — so the public array and the\n * registry can never drift apart. The manifest scanner is handled separately\n * (it parses JSON rather than running a Detector).\n */\nexport const detectors: Detector[] = builtinDetectors;\n\n/** Stable comparator: by file, then line, then ruleId. Exported for reuse. */\nexport function compareFindings(a: Finding, b: Finding): number {\n if (a.location.file !== b.location.file) return a.location.file < b.location.file ? -1 : 1;\n if (a.location.line !== b.location.line) return a.location.line - b.location.line;\n return a.ruleId < b.ruleId ? -1 : a.ruleId > b.ruleId ? 1 : 0;\n}\n\n/** Resolve the active detector list for a scan (override or the default registry). */\nfunction resolveDetectors(options: ScanOptions): Detector[] {\n return options.detectors ?? defaultRegistry.all();\n}\n\n/**\n * Run all applicable detectors + the manifest scanner over a single file's\n * contents, honouring the source / config / dependencies toggles. Pure: no I/O.\n * Exported so the parallel worker and unit tests can drive it directly.\n */\nexport function detectFile(\n file: string,\n content: string,\n dets: readonly Detector[],\n toggles: { source: boolean; config: boolean; deps: boolean },\n disabledRules?: readonly string[],\n): Finding[] {\n let out: Finding[] = [];\n\n for (const det of dets) {\n if (!det.appliesTo(file)) continue;\n const isConfig = detectorScope(det) === \"config\";\n if (isConfig ? !toggles.config : !toggles.source) continue;\n out.push(...det.detect({ file, content }));\n }\n\n // Drop lexical false positives that land inside comments (`// migrated off\n // createECDH()`), then honour inline `// qscan-ignore-line` /\n // `qscan-ignore-next-line` directives. Both run before the dependency scan\n // appends its findings (manifests carry neither).\n out = stripCommentFindings(out, content, file);\n out = stripStringLiteralFindings(out, content, file, CODE_ONLY_RULES);\n out = stripIgnoredFindings(out, content);\n\n if (toggles.deps && isManifestFile(file)) {\n out.push(...scanManifest(file, content));\n }\n\n // Per-rule suppression: drop findings whose ruleId was disabled. Applied here\n // so both the serial scan and the worker path honour it identically.\n if (disabledRules && disabledRules.length > 0) {\n const disabled = new Set(disabledRules);\n return out.filter((f) => !disabled.has(f.ruleId));\n }\n\n return out;\n}\n\n/**\n * Recursively scan a directory (or single file, or explicit file list) for\n * classical asymmetric crypto. Honours the source / dependencies / config\n * toggles (all default true) and reports progress through `options.onFile`.\n */\nexport async function scan(options: ScanOptions): Promise<ScanResult> {\n const startedAt = new Date();\n\n const doSource = options.source !== false;\n const doDeps = options.dependencies !== false;\n const doConfig = options.config !== false;\n const scanMinified = options.scanMinified === true;\n const dets = resolveDetectors(options);\n\n // Resolve whether the root is a file so we can rebuild absolute paths to read.\n const rootStat = await stat(options.root);\n const rootIsFile = rootStat.isFile();\n const baseDir = rootIsFile ? path.dirname(options.root) : options.root;\n const singleFileName = rootIsFile ? path.basename(options.root) : null;\n\n const findings: Finding[] = [];\n let filesScanned = 0;\n let analyzedFiles = 0;\n let bytesScanned = 0;\n let unreadable = 0;\n let skippedMinified = 0;\n\n // Optional content-hash scan cache: unchanged files reuse prior findings.\n const cacheFile = options.cacheFile;\n const ruleset = cacheFile ? rulesetFingerprint(dets, options.disabledRules) : \"\";\n const cache = cacheFile ? await loadCache(cacheFile, ruleset) : null;\n // A full scan starts with an empty next-cache so files that vanished are\n // evicted. An INCREMENTAL scan (explicit `files` list) only visits a subset,\n // so seed the next-cache with the existing entries — otherwise saving would\n // drop every file we didn't happen to scan this run (audit: arch #4).\n const incremental = Array.isArray(options.files);\n const nextEntries: Map<string, CacheEntry> | null = cacheFile\n ? new Map(incremental && cache ? cache : [])\n : null;\n\n // Work-budget / cancellation controls (all optional, unlimited when omitted).\n const signal = options.signal;\n const maxFiles = options.maxFiles;\n const maxBytes = options.maxBytes;\n\n // Source of relative paths: an explicit file list (incremental) or the walker.\n const relPaths: AsyncIterable<string> = options.files\n ? filterExplicitFiles(options.files, options)\n : walkFiles(options.root, {\n include: options.include,\n exclude: options.exclude,\n noDefaultIgnores: options.noDefaultIgnores,\n maxFileSize: options.maxFileSize,\n });\n\n for await (const rel of relPaths) {\n // Cooperative cancellation: check the signal at the top of every iteration.\n if (signal?.aborted) throw new AbortError();\n\n // File-count budget: enforced before reading the next file.\n if (typeof maxFiles === \"number\" && filesScanned >= maxFiles) {\n throw new BudgetExceededError(`maxFiles budget exceeded (limit: ${maxFiles}).`);\n }\n\n // In single-file mode, walkFiles yields the basename; map back to the file.\n const absPath = singleFileName ? options.root : path.join(baseDir, ...rel.split(\"/\"));\n const reportedPath = singleFileName ? toPosix(rel) : rel;\n\n options.onFile?.(reportedPath);\n\n // Cryptographic keystores (.jks/.p12/…) are binary; read them byte-preserving\n // (latin1) so the keystore detector can inspect magic bytes.\n const keystore = isKeystorePath(reportedPath);\n // Keystores are read whole into memory as latin1. The walker already caps file\n // size, but the explicit-file-list (incremental) path does not — so stat and\n // skip an oversized binary here to avoid reading a huge encrypted archive\n // (`.gpg`) into a string.\n if (keystore) {\n try {\n const { size } = await stat(absPath);\n if (size > (options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE)) continue;\n } catch {\n unreadable += 1;\n continue;\n }\n }\n let content: string;\n try {\n content = await readFile(absPath, keystore ? \"latin1\" : \"utf8\");\n } catch {\n unreadable += 1; // permissions / vanished / decode failure — tracked, not silent.\n continue;\n }\n\n // Skip machine-minified / generated content (unless explicitly enabled).\n // Manifests and keystores are always scanned.\n if (!scanMinified && !isManifestFile(reportedPath) && !keystore && looksMinified(content)) {\n skippedMinified += 1;\n continue;\n }\n\n // Cumulative-byte budget: enforced once this file's bytes are accounted for.\n // Use the read encoding so a latin1 keystore is counted at its on-disk size\n // (a utf8 byteLength would double-count every byte ≥ 0x80).\n bytesScanned += Buffer.byteLength(content, keystore ? \"latin1\" : \"utf8\");\n if (typeof maxBytes === \"number\" && bytesScanned > maxBytes) {\n throw new BudgetExceededError(`maxBytes budget exceeded (limit: ${maxBytes}).`);\n }\n\n filesScanned += 1;\n if (isAnalyzableSource(reportedPath)) analyzedFiles += 1;\n\n // Cache: reuse prior findings when the content hash matches; otherwise scan\n // and record. `nextEntries` becomes the new cache (dropping vanished files).\n let fileFindings: Finding[];\n if (cache && nextEntries) {\n const hash = hashContent(content);\n const hit = cache.get(reportedPath);\n fileFindings =\n hit && hit.hash === hash\n ? hit.findings\n : detectFile(\n reportedPath,\n content,\n dets,\n { source: doSource, config: doConfig, deps: doDeps },\n options.disabledRules,\n );\n nextEntries.set(reportedPath, { hash, findings: fileFindings });\n } else {\n fileFindings = detectFile(\n reportedPath,\n content,\n dets,\n { source: doSource, config: doConfig, deps: doDeps },\n options.disabledRules,\n );\n }\n findings.push(...fileFindings);\n }\n\n // Persist the cache (best effort) before ordering/returning.\n if (cacheFile && nextEntries) await saveCache(cacheFile, ruleset, nextEntries);\n\n // Stable ordering: by file, then line, then ruleId.\n findings.sort(compareFindings);\n\n const inventory = buildInventory(findings);\n const finishedAt = new Date();\n\n return {\n root: options.root,\n findings,\n filesScanned,\n analyzedFiles,\n diagnostics: { unreadable, skippedMinified },\n inventory,\n startedAt: startedAt.toISOString(),\n finishedAt: finishedAt.toISOString(),\n toolVersion: VERSION,\n };\n}\n\n/**\n * Filter an explicit relative file list down to the paths that pass the binary\n * filter and the include/exclude patterns, returning them deduped and sorted for\n * deterministic output. Size limits are enforced later (we still read manifests\n * over the cap). Non-existent files are simply skipped at read time.\n *\n * Pure + synchronous, and exported so the parallel enumerator applies the EXACT\n * same filtering for explicit file lists as the serial path (byte-for-byte\n * identical results under `--parallel`).\n */\nexport function filterExplicitFileList(\n files: readonly string[],\n options: Pick<ScanOptions, \"include\" | \"exclude\">,\n): string[] {\n const include = options.include ?? [];\n const exclude = options.exclude ?? [];\n const seen = new Set<string>();\n const list = [...files]\n .map((f) => toPosix(f))\n .filter((f) => {\n if (seen.has(f)) return false;\n seen.add(f);\n return true;\n })\n .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n\n return list.filter((rel) => {\n if (isBinaryPath(rel)) return false;\n if (include.length > 0 && !matchesAny(rel, include)) return false;\n if (matchesAny(rel, exclude)) return false;\n return true;\n });\n}\n\n/** Async-generator wrapper around {@link filterExplicitFileList} for `scan()`. */\nasync function* filterExplicitFiles(files: string[], options: ScanOptions): AsyncGenerator<string> {\n for (const rel of filterExplicitFileList(files, options)) yield rel;\n}\n"]}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Selectable STANDARDS PROFILES — the regime a scan's remediation, deadlines, and
3
+ * hybrid guidance are tailored to. Different national/regional authorities agree on
4
+ * the PQC primitives (ML-KEM / ML-DSA) but diverge on two things this tool must not
5
+ * hardcode: (a) the required PARAMETER SETS (a commercial ML-KEM-768 vs a
6
+ * national-security ML-KEM-1024), and (b) the HYBRID STANCE — whether classical+PQC
7
+ * hybridization is required, recommended, or optional during the transition. Baking
8
+ * in NIST/CNSA's "hybrids optional" is wrong for an ANSSI or BSI audience, where
9
+ * hybrid is required. `--profile <id>` selects the regime; `--policy` composes an
10
+ * org's own exceptions on top.
11
+ *
12
+ * Like {@link PqcStandards}, every profile carries a citation + `asOf` date and is
13
+ * re-verified on the quarterly standards cadence. These are guidance summaries, not
14
+ * legal advice — consult the cited source of record.
15
+ */
16
+ /** Whether classical+PQC hybridization is required during the transition, per regime. */
17
+ export type HybridStance = "required" | "recommended" | "optional";
18
+ /** A regime's PQC guidance profile. */
19
+ export interface StandardsProfile {
20
+ /** Stable id used by `--profile` (kebab-case). */
21
+ readonly id: string;
22
+ /** Human-readable name. */
23
+ readonly name: string;
24
+ /** The authority / document of record. */
25
+ readonly authority: string;
26
+ /** The KEM / signature parameter sets this regime calls for. */
27
+ readonly paramSets: {
28
+ readonly kem: string;
29
+ readonly signature: string;
30
+ };
31
+ /** Whether hybridization is required / recommended / optional under this regime. */
32
+ readonly hybridStance: HybridStance;
33
+ /** One-line regime-specific hybrid guidance surfaced in remediation. */
34
+ readonly hybridGuidance: string;
35
+ /** Year after which classical public-key crypto is deprecated under this regime. */
36
+ readonly deprecateAfter: number;
37
+ /** Year after which it is disallowed. */
38
+ readonly disallowAfter: number;
39
+ /** Spec identifier / publication of record. */
40
+ readonly citation: string;
41
+ /** `YYYY-MM` — when this profile was last verified against its source. */
42
+ readonly asOf: string;
43
+ }
44
+ /** The default profile id when `--profile` is not given. */
45
+ export declare const DEFAULT_PROFILE_ID = "nist";
46
+ /**
47
+ * Built-in regime profiles. Facts reflect each authority's published PQC-transition
48
+ * position as of the `asOf` date; verify against the cited source before relying on a
49
+ * deadline or a hybrid mandate for a compliance decision.
50
+ */
51
+ export declare const STANDARDS_PROFILES: Readonly<Record<string, StandardsProfile>>;
52
+ /** All built-in profile ids, in a stable order (default first). */
53
+ export declare function standardsProfileIds(): string[];
54
+ /** Look up a built-in profile by id, or `undefined` when unknown. */
55
+ export declare function getStandardsProfile(id: string): StandardsProfile | undefined;
56
+ /** The default profile (NIST). Always defined. */
57
+ export declare function defaultStandardsProfile(): StandardsProfile;
58
+ //# sourceMappingURL=standards-profiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standards-profiles.d.ts","sourceRoot":"","sources":["../src/standards-profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,yFAAyF;AACzF,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;AAEnE,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACzE,oFAAoF;IACpF,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,oFAAoF;IACpF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,yCAAyC;IACzC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,4DAA4D;AAC5D,eAAO,MAAM,kBAAkB,SAAS,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAkEzE,CAAC;AAEF,mEAAmE;AACnE,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAK9C;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAE5E;AAED,kDAAkD;AAClD,wBAAgB,uBAAuB,IAAI,gBAAgB,CAE1D"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Selectable STANDARDS PROFILES — the regime a scan's remediation, deadlines, and
3
+ * hybrid guidance are tailored to. Different national/regional authorities agree on
4
+ * the PQC primitives (ML-KEM / ML-DSA) but diverge on two things this tool must not
5
+ * hardcode: (a) the required PARAMETER SETS (a commercial ML-KEM-768 vs a
6
+ * national-security ML-KEM-1024), and (b) the HYBRID STANCE — whether classical+PQC
7
+ * hybridization is required, recommended, or optional during the transition. Baking
8
+ * in NIST/CNSA's "hybrids optional" is wrong for an ANSSI or BSI audience, where
9
+ * hybrid is required. `--profile <id>` selects the regime; `--policy` composes an
10
+ * org's own exceptions on top.
11
+ *
12
+ * Like {@link PqcStandards}, every profile carries a citation + `asOf` date and is
13
+ * re-verified on the quarterly standards cadence. These are guidance summaries, not
14
+ * legal advice — consult the cited source of record.
15
+ */
16
+ /** The default profile id when `--profile` is not given. */
17
+ export const DEFAULT_PROFILE_ID = "nist";
18
+ /**
19
+ * Built-in regime profiles. Facts reflect each authority's published PQC-transition
20
+ * position as of the `asOf` date; verify against the cited source before relying on a
21
+ * deadline or a hybrid mandate for a compliance decision.
22
+ */
23
+ export const STANDARDS_PROFILES = {
24
+ nist: {
25
+ id: "nist",
26
+ name: "NIST (general / commercial)",
27
+ authority: "NIST",
28
+ paramSets: { kem: "ML-KEM-768 (FIPS 203)", signature: "ML-DSA-65 (FIPS 204)" },
29
+ hybridStance: "recommended",
30
+ hybridGuidance: "Hybrid key establishment (e.g. X25519MLKEM768) is permitted and recommended during the transition; pure ML-KEM is also acceptable (SP 800-227 / IR 8547).",
31
+ deprecateAfter: 2030,
32
+ disallowAfter: 2035,
33
+ citation: "NIST IR 8547 + FIPS 203/204/205",
34
+ asOf: "2026-07",
35
+ },
36
+ "cnsa-2.0": {
37
+ id: "cnsa-2.0",
38
+ name: "NSA CNSA 2.0 (national-security systems)",
39
+ authority: "NSA",
40
+ paramSets: { kem: "ML-KEM-1024 (FIPS 203)", signature: "ML-DSA-87 (FIPS 204)" },
41
+ hybridStance: "optional",
42
+ hybridGuidance: "CNSA 2.0 targets pure PQC and does not require hybrids; if a hybrid TLS group is used, it must be SecP384r1MLKEM1024 — X25519MLKEM768's ML-KEM-768 component is sub-CNSA.",
43
+ deprecateAfter: 2030,
44
+ disallowAfter: 2035,
45
+ citation: "NSA CNSA 2.0 (2030/2033/2035 migration milestones)",
46
+ asOf: "2026-07",
47
+ },
48
+ "bsi-tr-02102": {
49
+ id: "bsi-tr-02102",
50
+ name: "BSI TR-02102 (Germany)",
51
+ authority: "BSI",
52
+ paramSets: { kem: "ML-KEM-768 (FIPS 203)", signature: "ML-DSA-65 (FIPS 204)" },
53
+ hybridStance: "required",
54
+ hybridGuidance: "BSI requires PQC be deployed in HYBRID with an established classical scheme during the transition (defense-in-depth); FrodoKEM is the conservative KEM alternative to ML-KEM, and XMSS/LMS are approved for firmware signing.",
55
+ deprecateAfter: 2030,
56
+ disallowAfter: 2035,
57
+ citation: "BSI TR-02102-1 (Kryptographische Verfahren)",
58
+ asOf: "2026-07",
59
+ },
60
+ anssi: {
61
+ id: "anssi",
62
+ name: "ANSSI (France)",
63
+ authority: "ANSSI",
64
+ paramSets: { kem: "ML-KEM-1024 (FIPS 203)", signature: "ML-DSA-87 (FIPS 204)" },
65
+ hybridStance: "required",
66
+ hybridGuidance: "ANSSI requires HYBRIDIZATION (classical + PQC) throughout the transition phase and does not endorse pure PQC alone yet; use the highest parameter set for long-lived assurance.",
67
+ deprecateAfter: 2030,
68
+ disallowAfter: 2035,
69
+ citation: "ANSSI — PQC transition position papers",
70
+ asOf: "2026-07",
71
+ },
72
+ "uk-ncsc": {
73
+ id: "uk-ncsc",
74
+ name: "UK NCSC",
75
+ authority: "NCSC",
76
+ paramSets: { kem: "ML-KEM-768 (FIPS 203)", signature: "ML-DSA-65 (FIPS 204)" },
77
+ hybridStance: "recommended",
78
+ hybridGuidance: "NCSC recommends ML-KEM / ML-DSA and is broadly agnostic on hybridization (recommended, not mandated); its migration milestones are earlier — discovery/plan by 2028, high-priority migration by 2031, complete by 2035.",
79
+ deprecateAfter: 2031,
80
+ disallowAfter: 2035,
81
+ citation: "NCSC — Preparing for quantum-safe cryptography / PQC migration timeline",
82
+ asOf: "2026-07",
83
+ },
84
+ };
85
+ /** All built-in profile ids, in a stable order (default first). */
86
+ export function standardsProfileIds() {
87
+ return [
88
+ DEFAULT_PROFILE_ID,
89
+ ...Object.keys(STANDARDS_PROFILES).filter((id) => id !== DEFAULT_PROFILE_ID),
90
+ ];
91
+ }
92
+ /** Look up a built-in profile by id, or `undefined` when unknown. */
93
+ export function getStandardsProfile(id) {
94
+ return STANDARDS_PROFILES[id];
95
+ }
96
+ /** The default profile (NIST). Always defined. */
97
+ export function defaultStandardsProfile() {
98
+ return STANDARDS_PROFILES[DEFAULT_PROFILE_ID];
99
+ }
100
+ //# sourceMappingURL=standards-profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standards-profiles.js","sourceRoot":"","sources":["../src/standards-profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA6BH,4DAA4D;AAC5D,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAEzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA+C;IAC5E,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,6BAA6B;QACnC,SAAS,EAAE,MAAM;QACjB,SAAS,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC9E,YAAY,EAAE,aAAa;QAC3B,cAAc,EACZ,2JAA2J;QAC7J,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,iCAAiC;QAC3C,IAAI,EAAE,SAAS;KAChB;IACD,UAAU,EAAE;QACV,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,0CAA0C;QAChD,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,EAAE,GAAG,EAAE,wBAAwB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC/E,YAAY,EAAE,UAAU;QACxB,cAAc,EACZ,2KAA2K;QAC7K,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,oDAAoD;QAC9D,IAAI,EAAE,SAAS;KAChB;IACD,cAAc,EAAE;QACd,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,wBAAwB;QAC9B,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC9E,YAAY,EAAE,UAAU;QACxB,cAAc,EACZ,+NAA+N;QACjO,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,6CAA6C;QACvD,IAAI,EAAE,SAAS;KAChB;IACD,KAAK,EAAE;QACL,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,gBAAgB;QACtB,SAAS,EAAE,OAAO;QAClB,SAAS,EAAE,EAAE,GAAG,EAAE,wBAAwB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC/E,YAAY,EAAE,UAAU;QACxB,cAAc,EACZ,iLAAiL;QACnL,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,wCAAwC;QAClD,IAAI,EAAE,SAAS;KAChB;IACD,SAAS,EAAE;QACT,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,SAAS;QACf,SAAS,EAAE,MAAM;QACjB,SAAS,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC9E,YAAY,EAAE,aAAa;QAC3B,cAAc,EACZ,yNAAyN;QAC3N,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,yEAAyE;QACnF,IAAI,EAAE,SAAS;KAChB;CACF,CAAC;AAEF,mEAAmE;AACnE,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,kBAAkB;QAClB,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,kBAAkB,CAAC;KAC7E,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,mBAAmB,CAAC,EAAU;IAC5C,OAAO,kBAAkB,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,uBAAuB;IACrC,OAAO,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;AAChD,CAAC","sourcesContent":["/**\n * Selectable STANDARDS PROFILES — the regime a scan's remediation, deadlines, and\n * hybrid guidance are tailored to. Different national/regional authorities agree on\n * the PQC primitives (ML-KEM / ML-DSA) but diverge on two things this tool must not\n * hardcode: (a) the required PARAMETER SETS (a commercial ML-KEM-768 vs a\n * national-security ML-KEM-1024), and (b) the HYBRID STANCE — whether classical+PQC\n * hybridization is required, recommended, or optional during the transition. Baking\n * in NIST/CNSA's \"hybrids optional\" is wrong for an ANSSI or BSI audience, where\n * hybrid is required. `--profile <id>` selects the regime; `--policy` composes an\n * org's own exceptions on top.\n *\n * Like {@link PqcStandards}, every profile carries a citation + `asOf` date and is\n * re-verified on the quarterly standards cadence. These are guidance summaries, not\n * legal advice — consult the cited source of record.\n */\n\n/** Whether classical+PQC hybridization is required during the transition, per regime. */\nexport type HybridStance = \"required\" | \"recommended\" | \"optional\";\n\n/** A regime's PQC guidance profile. */\nexport interface StandardsProfile {\n /** Stable id used by `--profile` (kebab-case). */\n readonly id: string;\n /** Human-readable name. */\n readonly name: string;\n /** The authority / document of record. */\n readonly authority: string;\n /** The KEM / signature parameter sets this regime calls for. */\n readonly paramSets: { readonly kem: string; readonly signature: string };\n /** Whether hybridization is required / recommended / optional under this regime. */\n readonly hybridStance: HybridStance;\n /** One-line regime-specific hybrid guidance surfaced in remediation. */\n readonly hybridGuidance: string;\n /** Year after which classical public-key crypto is deprecated under this regime. */\n readonly deprecateAfter: number;\n /** Year after which it is disallowed. */\n readonly disallowAfter: number;\n /** Spec identifier / publication of record. */\n readonly citation: string;\n /** `YYYY-MM` — when this profile was last verified against its source. */\n readonly asOf: string;\n}\n\n/** The default profile id when `--profile` is not given. */\nexport const DEFAULT_PROFILE_ID = \"nist\";\n\n/**\n * Built-in regime profiles. Facts reflect each authority's published PQC-transition\n * position as of the `asOf` date; verify against the cited source before relying on a\n * deadline or a hybrid mandate for a compliance decision.\n */\nexport const STANDARDS_PROFILES: Readonly<Record<string, StandardsProfile>> = {\n nist: {\n id: \"nist\",\n name: \"NIST (general / commercial)\",\n authority: \"NIST\",\n paramSets: { kem: \"ML-KEM-768 (FIPS 203)\", signature: \"ML-DSA-65 (FIPS 204)\" },\n hybridStance: \"recommended\",\n hybridGuidance:\n \"Hybrid key establishment (e.g. X25519MLKEM768) is permitted and recommended during the transition; pure ML-KEM is also acceptable (SP 800-227 / IR 8547).\",\n deprecateAfter: 2030,\n disallowAfter: 2035,\n citation: \"NIST IR 8547 + FIPS 203/204/205\",\n asOf: \"2026-07\",\n },\n \"cnsa-2.0\": {\n id: \"cnsa-2.0\",\n name: \"NSA CNSA 2.0 (national-security systems)\",\n authority: \"NSA\",\n paramSets: { kem: \"ML-KEM-1024 (FIPS 203)\", signature: \"ML-DSA-87 (FIPS 204)\" },\n hybridStance: \"optional\",\n hybridGuidance:\n \"CNSA 2.0 targets pure PQC and does not require hybrids; if a hybrid TLS group is used, it must be SecP384r1MLKEM1024 — X25519MLKEM768's ML-KEM-768 component is sub-CNSA.\",\n deprecateAfter: 2030,\n disallowAfter: 2035,\n citation: \"NSA CNSA 2.0 (2030/2033/2035 migration milestones)\",\n asOf: \"2026-07\",\n },\n \"bsi-tr-02102\": {\n id: \"bsi-tr-02102\",\n name: \"BSI TR-02102 (Germany)\",\n authority: \"BSI\",\n paramSets: { kem: \"ML-KEM-768 (FIPS 203)\", signature: \"ML-DSA-65 (FIPS 204)\" },\n hybridStance: \"required\",\n hybridGuidance:\n \"BSI requires PQC be deployed in HYBRID with an established classical scheme during the transition (defense-in-depth); FrodoKEM is the conservative KEM alternative to ML-KEM, and XMSS/LMS are approved for firmware signing.\",\n deprecateAfter: 2030,\n disallowAfter: 2035,\n citation: \"BSI TR-02102-1 (Kryptographische Verfahren)\",\n asOf: \"2026-07\",\n },\n anssi: {\n id: \"anssi\",\n name: \"ANSSI (France)\",\n authority: \"ANSSI\",\n paramSets: { kem: \"ML-KEM-1024 (FIPS 203)\", signature: \"ML-DSA-87 (FIPS 204)\" },\n hybridStance: \"required\",\n hybridGuidance:\n \"ANSSI requires HYBRIDIZATION (classical + PQC) throughout the transition phase and does not endorse pure PQC alone yet; use the highest parameter set for long-lived assurance.\",\n deprecateAfter: 2030,\n disallowAfter: 2035,\n citation: \"ANSSI — PQC transition position papers\",\n asOf: \"2026-07\",\n },\n \"uk-ncsc\": {\n id: \"uk-ncsc\",\n name: \"UK NCSC\",\n authority: \"NCSC\",\n paramSets: { kem: \"ML-KEM-768 (FIPS 203)\", signature: \"ML-DSA-65 (FIPS 204)\" },\n hybridStance: \"recommended\",\n hybridGuidance:\n \"NCSC recommends ML-KEM / ML-DSA and is broadly agnostic on hybridization (recommended, not mandated); its migration milestones are earlier — discovery/plan by 2028, high-priority migration by 2031, complete by 2035.\",\n deprecateAfter: 2031,\n disallowAfter: 2035,\n citation: \"NCSC — Preparing for quantum-safe cryptography / PQC migration timeline\",\n asOf: \"2026-07\",\n },\n};\n\n/** All built-in profile ids, in a stable order (default first). */\nexport function standardsProfileIds(): string[] {\n return [\n DEFAULT_PROFILE_ID,\n ...Object.keys(STANDARDS_PROFILES).filter((id) => id !== DEFAULT_PROFILE_ID),\n ];\n}\n\n/** Look up a built-in profile by id, or `undefined` when unknown. */\nexport function getStandardsProfile(id: string): StandardsProfile | undefined {\n return STANDARDS_PROFILES[id];\n}\n\n/** The default profile (NIST). Always defined. */\nexport function defaultStandardsProfile(): StandardsProfile {\n return STANDARDS_PROFILES[DEFAULT_PROFILE_ID];\n}\n"]}