@quantakrypto/core 0.4.4 → 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 (284) hide show
  1. package/README.md +76 -27
  2. package/dist/cbom-merge.d.ts.map +1 -1
  3. package/dist/cbom-merge.js +30 -8
  4. package/dist/cbom-merge.js.map +1 -1
  5. package/dist/cbom.d.ts +5 -0
  6. package/dist/cbom.d.ts.map +1 -1
  7. package/dist/cbom.js +132 -37
  8. package/dist/cbom.js.map +1 -1
  9. package/dist/comments.d.ts +2 -23
  10. package/dist/comments.d.ts.map +1 -1
  11. package/dist/comments.js +24 -5
  12. package/dist/comments.js.map +1 -1
  13. package/dist/detect-utils.d.ts +55 -21
  14. package/dist/detect-utils.d.ts.map +1 -1
  15. package/dist/detect-utils.js +133 -7
  16. package/dist/detect-utils.js.map +1 -1
  17. package/dist/detectors/age.d.ts +16 -0
  18. package/dist/detectors/age.d.ts.map +1 -0
  19. package/dist/detectors/age.js +40 -0
  20. package/dist/detectors/age.js.map +1 -0
  21. package/dist/detectors/ansible.d.ts +13 -0
  22. package/dist/detectors/ansible.d.ts.map +1 -0
  23. package/dist/detectors/ansible.js +108 -0
  24. package/dist/detectors/ansible.js.map +1 -0
  25. package/dist/detectors/bicep.d.ts +20 -0
  26. package/dist/detectors/bicep.d.ts.map +1 -0
  27. package/dist/detectors/bicep.js +74 -0
  28. package/dist/detectors/bicep.js.map +1 -0
  29. package/dist/detectors/c.d.ts.map +1 -1
  30. package/dist/detectors/c.js +30 -3
  31. package/dist/detectors/c.js.map +1 -1
  32. package/dist/detectors/cicd.d.ts.map +1 -1
  33. package/dist/detectors/cicd.js +18 -5
  34. package/dist/detectors/cicd.js.map +1 -1
  35. package/dist/detectors/cloud-kms.d.ts +8 -5
  36. package/dist/detectors/cloud-kms.d.ts.map +1 -1
  37. package/dist/detectors/cloud-kms.js +62 -20
  38. package/dist/detectors/cloud-kms.js.map +1 -1
  39. package/dist/detectors/cloudformation.d.ts +8 -0
  40. package/dist/detectors/cloudformation.d.ts.map +1 -1
  41. package/dist/detectors/cloudformation.js +41 -10
  42. package/dist/detectors/cloudformation.js.map +1 -1
  43. package/dist/detectors/codesign.d.ts +50 -0
  44. package/dist/detectors/codesign.d.ts.map +1 -0
  45. package/dist/detectors/codesign.js +143 -0
  46. package/dist/detectors/codesign.js.map +1 -0
  47. package/dist/detectors/csharp.d.ts.map +1 -1
  48. package/dist/detectors/csharp.js +13 -3
  49. package/dist/detectors/csharp.js.map +1 -1
  50. package/dist/detectors/dart.d.ts +35 -0
  51. package/dist/detectors/dart.d.ts.map +1 -0
  52. package/dist/detectors/dart.js +177 -0
  53. package/dist/detectors/dart.js.map +1 -0
  54. package/dist/detectors/database.d.ts +5 -3
  55. package/dist/detectors/database.d.ts.map +1 -1
  56. package/dist/detectors/database.js +45 -8
  57. package/dist/detectors/database.js.map +1 -1
  58. package/dist/detectors/dkim.d.ts +54 -0
  59. package/dist/detectors/dkim.d.ts.map +1 -0
  60. package/dist/detectors/dkim.js +92 -0
  61. package/dist/detectors/dkim.js.map +1 -0
  62. package/dist/detectors/dnssec.d.ts.map +1 -1
  63. package/dist/detectors/dnssec.js +19 -10
  64. package/dist/detectors/dnssec.js.map +1 -1
  65. package/dist/detectors/elixir.d.ts.map +1 -1
  66. package/dist/detectors/elixir.js +34 -2
  67. package/dist/detectors/elixir.js.map +1 -1
  68. package/dist/detectors/java.d.ts.map +1 -1
  69. package/dist/detectors/java.js +33 -3
  70. package/dist/detectors/java.js.map +1 -1
  71. package/dist/detectors/jose.d.ts.map +1 -1
  72. package/dist/detectors/jose.js +13 -3
  73. package/dist/detectors/jose.js.map +1 -1
  74. package/dist/detectors/jwk.d.ts +7 -7
  75. package/dist/detectors/jwk.d.ts.map +1 -1
  76. package/dist/detectors/jwk.js +44 -8
  77. package/dist/detectors/jwk.js.map +1 -1
  78. package/dist/detectors/k8s.d.ts.map +1 -1
  79. package/dist/detectors/k8s.js +5 -2
  80. package/dist/detectors/k8s.js.map +1 -1
  81. package/dist/detectors/keystore.d.ts +19 -0
  82. package/dist/detectors/keystore.d.ts.map +1 -0
  83. package/dist/detectors/keystore.js +76 -0
  84. package/dist/detectors/keystore.js.map +1 -0
  85. package/dist/detectors/mesh.d.ts +7 -8
  86. package/dist/detectors/mesh.d.ts.map +1 -1
  87. package/dist/detectors/mesh.js +17 -35
  88. package/dist/detectors/mesh.js.map +1 -1
  89. package/dist/detectors/messaging.d.ts +2 -2
  90. package/dist/detectors/messaging.d.ts.map +1 -1
  91. package/dist/detectors/messaging.js +19 -12
  92. package/dist/detectors/messaging.js.map +1 -1
  93. package/dist/detectors/objc.d.ts +41 -0
  94. package/dist/detectors/objc.d.ts.map +1 -0
  95. package/dist/detectors/objc.js +146 -0
  96. package/dist/detectors/objc.js.map +1 -0
  97. package/dist/detectors/openpgp.d.ts +20 -0
  98. package/dist/detectors/openpgp.d.ts.map +1 -0
  99. package/dist/detectors/openpgp.js +151 -0
  100. package/dist/detectors/openpgp.js.map +1 -0
  101. package/dist/detectors/pem.d.ts.map +1 -1
  102. package/dist/detectors/pem.js +32 -0
  103. package/dist/detectors/pem.js.map +1 -1
  104. package/dist/detectors/php.d.ts +2 -1
  105. package/dist/detectors/php.d.ts.map +1 -1
  106. package/dist/detectors/php.js +7 -3
  107. package/dist/detectors/php.js.map +1 -1
  108. package/dist/detectors/pkcs11.d.ts +17 -0
  109. package/dist/detectors/pkcs11.d.ts.map +1 -0
  110. package/dist/detectors/pkcs11.js +87 -0
  111. package/dist/detectors/pkcs11.js.map +1 -0
  112. package/dist/detectors/proxy.d.ts +52 -0
  113. package/dist/detectors/proxy.d.ts.map +1 -0
  114. package/dist/detectors/proxy.js +157 -0
  115. package/dist/detectors/proxy.js.map +1 -0
  116. package/dist/detectors/pulumi.d.ts +19 -0
  117. package/dist/detectors/pulumi.d.ts.map +1 -0
  118. package/dist/detectors/pulumi.js +80 -0
  119. package/dist/detectors/pulumi.js.map +1 -0
  120. package/dist/detectors/rust.d.ts.map +1 -1
  121. package/dist/detectors/rust.js +5 -0
  122. package/dist/detectors/rust.js.map +1 -1
  123. package/dist/detectors/secrets.d.ts +4 -1
  124. package/dist/detectors/secrets.d.ts.map +1 -1
  125. package/dist/detectors/secrets.js +5 -21
  126. package/dist/detectors/secrets.js.map +1 -1
  127. package/dist/detectors/solidity.d.ts +50 -0
  128. package/dist/detectors/solidity.d.ts.map +1 -0
  129. package/dist/detectors/solidity.js +108 -0
  130. package/dist/detectors/solidity.js.map +1 -0
  131. package/dist/detectors/source.d.ts.map +1 -1
  132. package/dist/detectors/source.js +53 -6
  133. package/dist/detectors/source.js.map +1 -1
  134. package/dist/detectors/spire.d.ts +49 -0
  135. package/dist/detectors/spire.d.ts.map +1 -0
  136. package/dist/detectors/spire.js +77 -0
  137. package/dist/detectors/spire.js.map +1 -0
  138. package/dist/detectors/ssh-ca.d.ts +72 -0
  139. package/dist/detectors/ssh-ca.d.ts.map +1 -0
  140. package/dist/detectors/ssh-ca.js +119 -0
  141. package/dist/detectors/ssh-ca.js.map +1 -0
  142. package/dist/detectors/supply-chain.d.ts +17 -0
  143. package/dist/detectors/supply-chain.d.ts.map +1 -0
  144. package/dist/detectors/supply-chain.js +89 -0
  145. package/dist/detectors/supply-chain.js.map +1 -0
  146. package/dist/detectors/swift.d.ts +22 -0
  147. package/dist/detectors/swift.d.ts.map +1 -0
  148. package/dist/detectors/swift.js +120 -0
  149. package/dist/detectors/swift.js.map +1 -0
  150. package/dist/detectors/terraform.d.ts.map +1 -1
  151. package/dist/detectors/terraform.js +35 -8
  152. package/dist/detectors/terraform.js.map +1 -1
  153. package/dist/detectors/vault.d.ts +15 -0
  154. package/dist/detectors/vault.d.ts.map +1 -0
  155. package/dist/detectors/vault.js +97 -0
  156. package/dist/detectors/vault.js.map +1 -0
  157. package/dist/detectors/vpn.d.ts +8 -8
  158. package/dist/detectors/vpn.d.ts.map +1 -1
  159. package/dist/detectors/vpn.js +12 -38
  160. package/dist/detectors/vpn.js.map +1 -1
  161. package/dist/detectors/weak-hash.d.ts +71 -0
  162. package/dist/detectors/weak-hash.d.ts.map +1 -0
  163. package/dist/detectors/weak-hash.js +116 -0
  164. package/dist/detectors/weak-hash.js.map +1 -0
  165. package/dist/detectors/webauthn.d.ts +61 -0
  166. package/dist/detectors/webauthn.d.ts.map +1 -0
  167. package/dist/detectors/webauthn.js +109 -0
  168. package/dist/detectors/webauthn.js.map +1 -0
  169. package/dist/detectors/xmldsig.d.ts +23 -0
  170. package/dist/detectors/xmldsig.d.ts.map +1 -0
  171. package/dist/detectors/xmldsig.js +84 -0
  172. package/dist/detectors/xmldsig.js.map +1 -0
  173. package/dist/evidence.d.ts +74 -4
  174. package/dist/evidence.d.ts.map +1 -1
  175. package/dist/evidence.js +71 -0
  176. package/dist/evidence.js.map +1 -1
  177. package/dist/index.d.ts +14 -11
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +17 -11
  180. package/dist/index.js.map +1 -1
  181. package/dist/inventory.d.ts +0 -2
  182. package/dist/inventory.d.ts.map +1 -1
  183. package/dist/inventory.js +15 -6
  184. package/dist/inventory.js.map +1 -1
  185. package/dist/registry.d.ts +9 -4
  186. package/dist/registry.d.ts.map +1 -1
  187. package/dist/registry.js +51 -4
  188. package/dist/registry.js.map +1 -1
  189. package/dist/remediate-pipeline.d.ts +0 -3
  190. package/dist/remediate-pipeline.d.ts.map +1 -1
  191. package/dist/remediate-pipeline.js +1 -1
  192. package/dist/remediate-pipeline.js.map +1 -1
  193. package/dist/remediation.d.ts +10 -0
  194. package/dist/remediation.d.ts.map +1 -1
  195. package/dist/remediation.js +32 -0
  196. package/dist/remediation.js.map +1 -1
  197. package/dist/report.d.ts +9 -0
  198. package/dist/report.d.ts.map +1 -1
  199. package/dist/report.js +31 -1
  200. package/dist/report.js.map +1 -1
  201. package/dist/scan-worker.js +5 -3
  202. package/dist/scan-worker.js.map +1 -1
  203. package/dist/scan.d.ts.map +1 -1
  204. package/dist/scan.js +35 -6
  205. package/dist/scan.js.map +1 -1
  206. package/dist/standards-profiles.d.ts +58 -0
  207. package/dist/standards-profiles.d.ts.map +1 -0
  208. package/dist/standards-profiles.js +100 -0
  209. package/dist/standards-profiles.js.map +1 -0
  210. package/dist/types.d.ts +6 -5
  211. package/dist/types.d.ts.map +1 -1
  212. package/dist/types.js.map +1 -1
  213. package/dist/version.d.ts +1 -1
  214. package/dist/version.js +1 -1
  215. package/dist/version.js.map +1 -1
  216. package/dist/vex.d.ts +39 -0
  217. package/dist/vex.d.ts.map +1 -0
  218. package/dist/vex.js +87 -0
  219. package/dist/vex.js.map +1 -0
  220. package/dist/walk.d.ts +8 -3
  221. package/dist/walk.d.ts.map +1 -1
  222. package/dist/walk.js +32 -1
  223. package/dist/walk.js.map +1 -1
  224. package/package.json +1 -1
  225. package/src/cbom-merge.ts +38 -8
  226. package/src/cbom.ts +153 -39
  227. package/src/comments.ts +25 -6
  228. package/src/detect-utils.ts +133 -11
  229. package/src/detectors/age.ts +60 -0
  230. package/src/detectors/ansible.ts +140 -0
  231. package/src/detectors/bicep.ts +107 -0
  232. package/src/detectors/c.ts +31 -3
  233. package/src/detectors/cicd.ts +18 -5
  234. package/src/detectors/cloud-kms.ts +79 -25
  235. package/src/detectors/cloudformation.ts +45 -10
  236. package/src/detectors/codesign.ts +214 -0
  237. package/src/detectors/csharp.ts +13 -3
  238. package/src/detectors/dart.ts +237 -0
  239. package/src/detectors/database.ts +64 -11
  240. package/src/detectors/dkim.ts +172 -0
  241. package/src/detectors/dnssec.ts +19 -10
  242. package/src/detectors/elixir.ts +33 -2
  243. package/src/detectors/java.ts +37 -3
  244. package/src/detectors/jose.ts +19 -3
  245. package/src/detectors/jwk.ts +59 -17
  246. package/src/detectors/k8s.ts +5 -2
  247. package/src/detectors/keystore.ts +109 -0
  248. package/src/detectors/mesh.ts +21 -45
  249. package/src/detectors/messaging.ts +22 -14
  250. package/src/detectors/objc.ts +209 -0
  251. package/src/detectors/openpgp.ts +194 -0
  252. package/src/detectors/pem.ts +30 -0
  253. package/src/detectors/php.ts +9 -4
  254. package/src/detectors/pkcs11.ts +113 -0
  255. package/src/detectors/proxy.ts +236 -0
  256. package/src/detectors/pulumi.ts +106 -0
  257. package/src/detectors/rust.ts +5 -0
  258. package/src/detectors/secrets.ts +15 -26
  259. package/src/detectors/solidity.ts +176 -0
  260. package/src/detectors/source.ts +48 -5
  261. package/src/detectors/spire.ts +143 -0
  262. package/src/detectors/ssh-ca.ts +215 -0
  263. package/src/detectors/supply-chain.ts +117 -0
  264. package/src/detectors/swift.ts +149 -0
  265. package/src/detectors/terraform.ts +42 -8
  266. package/src/detectors/vault.ts +120 -0
  267. package/src/detectors/vpn.ts +20 -48
  268. package/src/detectors/weak-hash.ts +217 -0
  269. package/src/detectors/webauthn.ts +205 -0
  270. package/src/detectors/xmldsig.ts +115 -0
  271. package/src/evidence.ts +127 -4
  272. package/src/index.ts +41 -13
  273. package/src/inventory.ts +15 -7
  274. package/src/registry.ts +51 -4
  275. package/src/remediate-pipeline.ts +1 -1
  276. package/src/remediation.ts +39 -0
  277. package/src/report.ts +36 -1
  278. package/src/scan-worker.ts +5 -3
  279. package/src/scan.ts +41 -6
  280. package/src/standards-profiles.ts +136 -0
  281. package/src/types.ts +9 -4
  282. package/src/version.ts +1 -1
  283. package/src/vex.ts +122 -0
  284. package/src/walk.ts +33 -2
package/dist/walk.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"walk.js","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Filesystem walker. A zero-dependency recursive async generator that yields\n * scannable text files as relative POSIX paths. It honours a default ignore\n * list, user-supplied exclude patterns, a max file size, and a binary-extension\n * filter. The root may be a directory or a single file.\n */\nimport { readdir, stat } from \"node:fs/promises\";\nimport type { Dirent } from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport { isManifestFile } from \"./dependencies.js\";\n\n/** Directories ignored by default (can be disabled with noDefaultIgnores). */\nexport const DEFAULT_IGNORES: readonly string[] = [\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".next\",\n \"out\",\n \"coverage\",\n \"vendor\",\n \".turbo\",\n \".cache\",\n];\n\n/** Default maximum file size to read: 2 MiB. */\nexport const DEFAULT_MAX_FILE_SIZE = 2 * 1024 * 1024;\n\n/**\n * File extensions we treat as binary / non-text and therefore skip. Keeping this\n * as an extension allow-list-by-exclusion is cheap and avoids reading bytes.\n */\nconst BINARY_EXTENSIONS = new Set<string>([\n // images\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".webp\",\n \".bmp\",\n \".ico\",\n \".tiff\",\n \".avif\",\n // fonts\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".otf\",\n \".eot\",\n // archives / compressed\n \".zip\",\n \".gz\",\n \".tgz\",\n \".bz2\",\n \".xz\",\n \".7z\",\n \".rar\",\n \".tar\",\n // media\n \".mp3\",\n \".mp4\",\n \".mov\",\n \".avi\",\n \".mkv\",\n \".wav\",\n \".flac\",\n \".ogg\",\n \".webm\",\n // documents / binaries\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".exe\",\n \".dll\",\n \".so\",\n \".dylib\",\n \".bin\",\n \".o\",\n \".a\",\n \".class\",\n \".wasm\",\n // data blobs / db\n \".db\",\n \".sqlite\",\n \".sqlite3\",\n \".dat\",\n \".pack\",\n \".idx\",\n // misc\n \".lock\",\n \".map\",\n \".min.js\",\n \".node\",\n]);\n\n/** Options accepted by {@link walkFiles}. */\nexport interface WalkOptions {\n /**\n * Restrict to paths matching one of these include patterns (substring or\n * relative-path-prefix match). When omitted/empty, all files pass.\n */\n include?: string[];\n /** Extra exclude patterns (substring or relative-path-prefix match). */\n exclude?: string[];\n /** Disable the built-in directory ignore list. */\n noDefaultIgnores?: boolean;\n /** Max file size in bytes; larger files are skipped. */\n maxFileSize?: number;\n}\n\n/** Normalise a path to forward-slash POSIX separators. */\nexport function toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n\n/** A pattern is treated as a glob when it contains one of these metacharacters. */\nfunction hasGlobMeta(pattern: string): boolean {\n return /[*?[]/.test(pattern);\n}\n\n/**\n * Translate a glob into an anchored RegExp: `*` matches within a path segment\n * (not `/`), `**` matches across segments, a leading `**` before a slash is an\n * optional path prefix, `?` matches a single non-`/` char, `[...]` is a\n * character class. Other regex\n * metacharacters are escaped.\n */\nfunction globToRegExp(glob: string): RegExp {\n let re = \"\";\n for (let i = 0; i < glob.length; i++) {\n const c = glob[i];\n if (c === \"*\") {\n if (glob[i + 1] === \"*\") {\n i++; // consume the second '*'\n if (glob[i + 1] === \"/\") {\n i++; // consume the trailing '/'\n re += \"(?:.*/)?\"; // zero or more path segments\n } else {\n re += \".*\"; // '**' spanning segments\n }\n } else {\n re += \"[^/]*\"; // '*' within a segment\n }\n } else if (c === \"?\") {\n re += \"[^/]\";\n } else if (c === \"[\") {\n // Pass a character class through; find its closing ']'.\n const end = glob.indexOf(\"]\", i + 1);\n if (end === -1) {\n re += \"\\\\[\";\n } else {\n re += glob.slice(i, end + 1);\n i = end;\n }\n } else if (\"\\\\^$.|+(){}\".includes(c)) {\n re += \"\\\\\" + c;\n } else {\n re += c;\n }\n }\n return new RegExp(`^${re}$`);\n}\n\n/** Memoized glob→RegExp so a pattern is compiled once, not once per file. */\nconst GLOB_CACHE = new Map<string, RegExp>();\nfunction globRegExp(pattern: string): RegExp {\n let re = GLOB_CACHE.get(pattern);\n if (!re) {\n re = globToRegExp(pattern);\n GLOB_CACHE.set(pattern, re);\n }\n return re;\n}\n\n/**\n * True if `rel` (a POSIX relative path) matches any pattern. A pattern with a\n * glob metacharacter (`*`, `?`, `[`) is matched as an anchored glob; a plain\n * pattern keeps the historical substring / path-prefix semantics (so `\"src\"`\n * still matches `src/a.ts` and `\"secrets\"` matches anywhere).\n */\nexport function matchesAny(rel: string, patterns: readonly string[]): boolean {\n for (const pattern of patterns) {\n if (!pattern) continue;\n const p = toPosix(pattern).replace(/\\/+$/, \"\");\n if (hasGlobMeta(p)) {\n if (globRegExp(p).test(rel)) return true;\n continue;\n }\n // Plain pattern: substring match (handles \"src/legacy\" or \"secrets\")...\n if (rel.includes(p)) return true;\n // ...and explicit path-prefix match (\"foo\" should match \"foo/bar.ts\").\n if (rel === p || rel.startsWith(`${p}/`)) return true;\n }\n return false;\n}\n\n/** True if `rel` (a POSIX relative path) matches any exclude pattern. */\nfunction isExcluded(rel: string, exclude: readonly string[]): boolean {\n return matchesAny(rel, exclude);\n}\n\n/**\n * True if `rel` passes the include filter. An empty include list means \"include\n * everything\"; otherwise the file must match at least one include pattern.\n */\nfunction isIncluded(rel: string, include: readonly string[]): boolean {\n if (include.length === 0) return true;\n return matchesAny(rel, include);\n}\n\n/** True if the file's extension marks it as binary / non-text. */\nexport function isBinaryPath(rel: string): boolean {\n const lower = rel.toLowerCase();\n // Handle compound extensions like \".min.js\" first.\n if (lower.endsWith(\".min.js\")) return true;\n const ext = path.posix.extname(lower);\n return BINARY_EXTENSIONS.has(ext);\n}\n\n/**\n * Compound / pattern extensions that mark generated or bundled output we skip\n * by default (beyond `.min.js` / `.map`, which {@link isBinaryPath} handles).\n */\nconst GENERATED_PATH_RE =\n /(?:\\.min\\.[mc]?js|[.-]min\\.[mc]?js|\\.bundle\\.[mc]?js|\\.chunk\\.[mc]?js|\\.generated\\.[jt]sx?|_pb\\.js|\\.pb\\.go)$/i;\n\n/** True if the path looks like generated / bundled output (by name). */\nexport function isGeneratedPath(rel: string): boolean {\n return GENERATED_PATH_RE.test(rel.toLowerCase());\n}\n\n/**\n * Heuristic content check for machine-minified / generated files with no\n * telltale extension: a very long average line length, or any single line over\n * ~50 KB, in the first ~64 KB sampled. Used at read time, not in the walker.\n */\nexport function looksMinified(content: string): boolean {\n const sample = content.length > 65_536 ? content.slice(0, 65_536) : content;\n if (sample.length === 0) return false;\n let maxLine = 0;\n let cur = 0;\n let lines = 1;\n for (let i = 0; i < sample.length; i++) {\n if (sample.charCodeAt(i) === 10 /* \\n */) {\n if (cur > maxLine) maxLine = cur;\n cur = 0;\n lines++;\n } else {\n cur++;\n }\n }\n if (cur > maxLine) maxLine = cur;\n if (maxLine > 50_000) return true;\n const avgLine = sample.length / lines;\n return avgLine > 1_000;\n}\n\n/**\n * Recursively yield scannable file paths (relative to `root`, POSIX) under a\n * directory. If `root` points at a single file, yields just that file's\n * basename (subject to the size / binary filters).\n */\nexport async function* walkFiles(root: string, options: WalkOptions = {}): AsyncGenerator<string> {\n const include = options.include ?? [];\n const exclude = options.exclude ?? [];\n const maxFileSize = options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;\n const ignores = options.noDefaultIgnores ? [] : DEFAULT_IGNORES;\n\n const rootStat = await stat(root);\n\n // Single-file mode: yield the file itself (by basename) if it passes filters.\n if (rootStat.isFile()) {\n const name = toPosix(path.basename(root));\n if (\n !isBinaryPath(name) &&\n isIncluded(name, include) &&\n passesSizeLimit(name, rootStat.size, maxFileSize)\n ) {\n yield name;\n }\n return;\n }\n\n yield* walkDir(root, \"\", { include, exclude, maxFileSize, ignores });\n}\n\ninterface WalkContext {\n include: readonly string[];\n exclude: readonly string[];\n maxFileSize: number;\n ignores: readonly string[];\n}\n\n/**\n * True if a file passes the size limit. Dependency manifests (package.json /\n * package-lock.json) are exempt from the cap so large lockfiles still get\n * scanned for vulnerable dependencies instead of being silently dropped.\n */\nfunction passesSizeLimit(rel: string, size: number, maxFileSize: number): boolean {\n // Dependency manifests are always read (they can exceed the size cap but carry\n // the whole dependency tree). Uses the single {@link isManifestFile} definition.\n if (isManifestFile(rel)) return true;\n return size <= maxFileSize;\n}\n\n/** Internal recursive directory walker. `relDir` is POSIX-relative to the root. */\nasync function* walkDir(absDir: string, relDir: string, ctx: WalkContext): AsyncGenerator<string> {\n let entries: Dirent[];\n try {\n entries = await readdir(absDir, { withFileTypes: true });\n } catch {\n // Unreadable directory (permissions, transient races) — skip silently.\n return;\n }\n\n // Stable, deterministic ordering for reproducible scans.\n entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));\n\n for (const entry of entries) {\n const rel = relDir ? `${relDir}/${entry.name}` : entry.name;\n const abs = path.join(absDir, entry.name);\n\n if (entry.isSymbolicLink()) {\n // Don't follow symlinks: avoids cycles and escaping the root.\n continue;\n }\n\n if (entry.isDirectory()) {\n if (ctx.ignores.includes(entry.name)) continue;\n if (isExcluded(rel, ctx.exclude)) continue;\n yield* walkDir(abs, rel, ctx);\n continue;\n }\n\n if (!entry.isFile()) continue;\n if (isExcluded(rel, ctx.exclude)) continue;\n if (!isIncluded(rel, ctx.include)) continue;\n // Dependency manifests (incl. yarn.lock / pnpm-lock.yaml) are always read —\n // they carry the dependency tree and must not be dropped as binary/generated.\n const manifest = isManifestFile(rel);\n if (!manifest && isBinaryPath(rel)) continue;\n if (!manifest && isGeneratedPath(rel)) continue;\n\n try {\n const s = await stat(abs);\n if (!passesSizeLimit(rel, s.size, ctx.maxFileSize)) continue;\n } catch {\n continue;\n }\n\n yield rel;\n }\n}\n"]}
1
+ {"version":3,"file":"walk.js","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Filesystem walker. A zero-dependency recursive async generator that yields\n * scannable text files as relative POSIX paths. It honours a default ignore\n * list, user-supplied exclude patterns, a max file size, and a binary-extension\n * filter. The root may be a directory or a single file.\n */\nimport { readdir, stat } from \"node:fs/promises\";\nimport type { Dirent } from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport { isManifestFile } from \"./dependencies.js\";\n\n/** Directories ignored by default (can be disabled with noDefaultIgnores). */\nconst DEFAULT_IGNORES: readonly string[] = [\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".next\",\n \"out\",\n \"coverage\",\n \"vendor\",\n \".turbo\",\n \".cache\",\n];\n\n/** Default maximum file size to read: 2 MiB. */\nexport const DEFAULT_MAX_FILE_SIZE = 2 * 1024 * 1024;\n\n/**\n * File extensions we treat as binary / non-text and therefore skip. Keeping this\n * as an extension allow-list-by-exclusion is cheap and avoids reading bytes.\n */\nconst BINARY_EXTENSIONS = new Set<string>([\n // images\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".webp\",\n \".bmp\",\n \".ico\",\n \".tiff\",\n \".avif\",\n // fonts\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".otf\",\n \".eot\",\n // archives / compressed\n \".zip\",\n \".gz\",\n \".tgz\",\n \".bz2\",\n \".xz\",\n \".7z\",\n \".rar\",\n \".tar\",\n // media\n \".mp3\",\n \".mp4\",\n \".mov\",\n \".avi\",\n \".mkv\",\n \".wav\",\n \".flac\",\n \".ogg\",\n \".webm\",\n // documents / binaries\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".exe\",\n \".dll\",\n \".so\",\n \".dylib\",\n \".bin\",\n \".o\",\n \".a\",\n \".class\",\n \".wasm\",\n // data blobs / db\n \".db\",\n \".sqlite\",\n \".sqlite3\",\n \".dat\",\n \".pack\",\n \".idx\",\n // misc\n \".lock\",\n \".map\",\n \".min.js\",\n \".node\",\n]);\n\n/** Options accepted by {@link walkFiles}. */\ninterface WalkOptions {\n /**\n * Restrict to paths matching one of these include patterns (substring or\n * relative-path-prefix match). When omitted/empty, all files pass.\n */\n include?: string[];\n /** Extra exclude patterns (substring or relative-path-prefix match). */\n exclude?: string[];\n /** Disable the built-in directory ignore list. */\n noDefaultIgnores?: boolean;\n /** Max file size in bytes; larger files are skipped. */\n maxFileSize?: number;\n}\n\n/** Normalise a path to forward-slash POSIX separators. */\nexport function toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n\n/** A pattern is treated as a glob when it contains one of these metacharacters. */\nfunction hasGlobMeta(pattern: string): boolean {\n return /[*?[]/.test(pattern);\n}\n\n/**\n * Translate a glob into an anchored RegExp: `*` matches within a path segment\n * (not `/`), `**` matches across segments, a leading `**` before a slash is an\n * optional path prefix, `?` matches a single non-`/` char, `[...]` is a\n * character class. Other regex\n * metacharacters are escaped.\n */\nfunction globToRegExp(glob: string): RegExp {\n let re = \"\";\n for (let i = 0; i < glob.length; i++) {\n const c = glob[i];\n if (c === \"*\") {\n if (glob[i + 1] === \"*\") {\n i++; // consume the second '*'\n if (glob[i + 1] === \"/\") {\n i++; // consume the trailing '/'\n re += \"(?:.*/)?\"; // zero or more path segments\n } else {\n re += \".*\"; // '**' spanning segments\n }\n } else {\n re += \"[^/]*\"; // '*' within a segment\n }\n } else if (c === \"?\") {\n re += \"[^/]\";\n } else if (c === \"[\") {\n // Pass a character class through; find its closing ']'.\n const end = glob.indexOf(\"]\", i + 1);\n if (end === -1) {\n re += \"\\\\[\";\n } else {\n re += glob.slice(i, end + 1);\n i = end;\n }\n } else if (\"\\\\^$.|+(){}\".includes(c)) {\n re += \"\\\\\" + c;\n } else {\n re += c;\n }\n }\n return new RegExp(`^${re}$`);\n}\n\n/** Memoized glob→RegExp so a pattern is compiled once, not once per file. */\nconst GLOB_CACHE = new Map<string, RegExp>();\nfunction globRegExp(pattern: string): RegExp {\n let re = GLOB_CACHE.get(pattern);\n if (!re) {\n re = globToRegExp(pattern);\n GLOB_CACHE.set(pattern, re);\n }\n return re;\n}\n\n/**\n * True if `rel` (a POSIX relative path) matches any pattern. A pattern with a\n * glob metacharacter (`*`, `?`, `[`) is matched as an anchored glob; a plain\n * pattern keeps the historical substring / path-prefix semantics (so `\"src\"`\n * still matches `src/a.ts` and `\"secrets\"` matches anywhere).\n */\nexport function matchesAny(rel: string, patterns: readonly string[]): boolean {\n for (const pattern of patterns) {\n if (!pattern) continue;\n const p = toPosix(pattern).replace(/\\/+$/, \"\");\n if (hasGlobMeta(p)) {\n if (globRegExp(p).test(rel)) return true;\n continue;\n }\n // Plain pattern: substring match (handles \"src/legacy\" or \"secrets\")...\n if (rel.includes(p)) return true;\n // ...and explicit path-prefix match (\"foo\" should match \"foo/bar.ts\").\n if (rel === p || rel.startsWith(`${p}/`)) return true;\n }\n return false;\n}\n\n/** True if `rel` (a POSIX relative path) matches any exclude pattern. */\nfunction isExcluded(rel: string, exclude: readonly string[]): boolean {\n return matchesAny(rel, exclude);\n}\n\n/**\n * True if `rel` passes the include filter. An empty include list means \"include\n * everything\"; otherwise the file must match at least one include pattern.\n */\nfunction isIncluded(rel: string, include: readonly string[]): boolean {\n if (include.length === 0) return true;\n return matchesAny(rel, include);\n}\n\n/** True if the file's extension marks it as binary / non-text. */\nexport function isBinaryPath(rel: string): boolean {\n const lower = rel.toLowerCase();\n // Handle compound extensions like \".min.js\" first.\n if (lower.endsWith(\".min.js\")) return true;\n const ext = path.posix.extname(lower);\n return BINARY_EXTENSIONS.has(ext);\n}\n\n/**\n * Binary cryptographic key containers we DO want to scan — Java/PKCS#12 keystores\n * and binary OpenPGP keyrings/messages. Unlike the images/archives above these are\n * read byte-preserving (latin1) and exempted from the minified skip, so the\n * keystore + openpgp detectors can identify them by magic number / packet tag.\n * Kept separate from {@link BINARY_EXTENSIONS} so those detectors can opt in.\n */\nconst KEYSTORE_EXTENSIONS = new Set<string>([\n \".jks\",\n \".keystore\",\n \".jceks\",\n \".bks\",\n \".p12\",\n \".pfx\",\n // Binary OpenPGP keyrings / messages (armored .asc is text; handled elsewhere).\n \".gpg\",\n \".pgp\",\n \".kbx\",\n]);\n\n/**\n * True if the path is a binary cryptographic key container we scan byte-preserving.\n * Uses a suffix match (not `extname`) so it agrees with the detectors' `hasExtension`\n * even for a bare dotfile literally named e.g. `.gpg` (where `extname` returns \"\").\n */\nexport function isKeystorePath(rel: string): boolean {\n const lower = rel.toLowerCase();\n for (const ext of KEYSTORE_EXTENSIONS) if (lower.endsWith(ext)) return true;\n return false;\n}\n\n/**\n * Compound / pattern extensions that mark generated or bundled output we skip\n * by default (beyond `.min.js` / `.map`, which {@link isBinaryPath} handles).\n */\nconst GENERATED_PATH_RE =\n /(?:\\.min\\.[mc]?js|[.-]min\\.[mc]?js|\\.bundle\\.[mc]?js|\\.chunk\\.[mc]?js|\\.generated\\.[jt]sx?|_pb\\.js|\\.pb\\.go)$/i;\n\n/** True if the path looks like generated / bundled output (by name). */\nexport function isGeneratedPath(rel: string): boolean {\n return GENERATED_PATH_RE.test(rel.toLowerCase());\n}\n\n/**\n * Heuristic content check for machine-minified / generated files with no\n * telltale extension: a very long average line length, or any single line over\n * ~50 KB, in the first ~64 KB sampled. Used at read time, not in the walker.\n */\nexport function looksMinified(content: string): boolean {\n const sample = content.length > 65_536 ? content.slice(0, 65_536) : content;\n if (sample.length === 0) return false;\n let maxLine = 0;\n let cur = 0;\n let lines = 1;\n for (let i = 0; i < sample.length; i++) {\n if (sample.charCodeAt(i) === 10 /* \\n */) {\n if (cur > maxLine) maxLine = cur;\n cur = 0;\n lines++;\n } else {\n cur++;\n }\n }\n if (cur > maxLine) maxLine = cur;\n if (maxLine > 50_000) return true;\n const avgLine = sample.length / lines;\n return avgLine > 1_000;\n}\n\n/**\n * Recursively yield scannable file paths (relative to `root`, POSIX) under a\n * directory. If `root` points at a single file, yields just that file's\n * basename (subject to the size / binary filters).\n */\nexport async function* walkFiles(root: string, options: WalkOptions = {}): AsyncGenerator<string> {\n const include = options.include ?? [];\n const exclude = options.exclude ?? [];\n const maxFileSize = options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;\n const ignores = options.noDefaultIgnores ? [] : DEFAULT_IGNORES;\n\n const rootStat = await stat(root);\n\n // Single-file mode: yield the file itself (by basename) if it passes filters.\n if (rootStat.isFile()) {\n const name = toPosix(path.basename(root));\n if (\n !isBinaryPath(name) &&\n isIncluded(name, include) &&\n passesSizeLimit(name, rootStat.size, maxFileSize)\n ) {\n yield name;\n }\n return;\n }\n\n yield* walkDir(root, \"\", { include, exclude, maxFileSize, ignores });\n}\n\ninterface WalkContext {\n include: readonly string[];\n exclude: readonly string[];\n maxFileSize: number;\n ignores: readonly string[];\n}\n\n/**\n * True if a file passes the size limit. Dependency manifests (package.json /\n * package-lock.json) are exempt from the cap so large lockfiles still get\n * scanned for vulnerable dependencies instead of being silently dropped.\n */\nfunction passesSizeLimit(rel: string, size: number, maxFileSize: number): boolean {\n // Dependency manifests are always read (they can exceed the size cap but carry\n // the whole dependency tree). Uses the single {@link isManifestFile} definition.\n if (isManifestFile(rel)) return true;\n return size <= maxFileSize;\n}\n\n/** Internal recursive directory walker. `relDir` is POSIX-relative to the root. */\nasync function* walkDir(absDir: string, relDir: string, ctx: WalkContext): AsyncGenerator<string> {\n let entries: Dirent[];\n try {\n entries = await readdir(absDir, { withFileTypes: true });\n } catch {\n // Unreadable directory (permissions, transient races) — skip silently.\n return;\n }\n\n // Stable, deterministic ordering for reproducible scans.\n entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));\n\n for (const entry of entries) {\n const rel = relDir ? `${relDir}/${entry.name}` : entry.name;\n const abs = path.join(absDir, entry.name);\n\n if (entry.isSymbolicLink()) {\n // Don't follow symlinks: avoids cycles and escaping the root.\n continue;\n }\n\n if (entry.isDirectory()) {\n if (ctx.ignores.includes(entry.name)) continue;\n if (isExcluded(rel, ctx.exclude)) continue;\n yield* walkDir(abs, rel, ctx);\n continue;\n }\n\n if (!entry.isFile()) continue;\n if (isExcluded(rel, ctx.exclude)) continue;\n if (!isIncluded(rel, ctx.include)) continue;\n // Dependency manifests (incl. yarn.lock / pnpm-lock.yaml) are always read —\n // they carry the dependency tree and must not be dropped as binary/generated.\n const manifest = isManifestFile(rel);\n if (!manifest && isBinaryPath(rel)) continue;\n if (!manifest && isGeneratedPath(rel)) continue;\n\n try {\n const s = await stat(abs);\n if (!passesSizeLimit(rel, s.size, ctx.maxFileSize)) continue;\n } catch {\n continue;\n }\n\n yield rel;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantakrypto/core",
3
- "version": "0.4.4",
3
+ "version": "0.5.0",
4
4
  "description": "Shared post-quantum readiness library: crypto detectors, vulnerable-dependency database, inventory + SARIF reporting. Zero runtime dependencies.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Dandelion Labs <hello@dandelionlabs.io> (https://dandelionlabs.io)",
package/src/cbom-merge.ts CHANGED
@@ -26,12 +26,29 @@ function occurrencesOf(c: CbomComponent): Occurrence[] {
26
26
  return Array.isArray(occ) ? (occ as Occurrence[]) : [];
27
27
  }
28
28
 
29
+ const HNDL_PROP = "quantakrypto:harvestNowDecryptLater";
30
+
29
31
  function hndlOf(c: CbomComponent): boolean {
32
+ // The flag is carried as a CycloneDX component `property` (name/value). Fall back
33
+ // to the legacy `cryptoProperties.harvestNowDecryptLater` location so an
34
+ // externally-authored / older CBOM still merges correctly.
35
+ const prop = c.properties?.find((p) => p.name === HNDL_PROP);
36
+ if (prop) return prop.value === "true";
30
37
  return (
31
- (c.cryptoProperties as { harvestNowDecryptLater?: unknown }).harvestNowDecryptLater === true
38
+ (c.cryptoProperties as { harvestNowDecryptLater?: unknown } | undefined)
39
+ ?.harvestNowDecryptLater === true
32
40
  );
33
41
  }
34
42
 
43
+ /** Return a copy of `props` with the HNDL flag set to `value`. */
44
+ function withHndl(
45
+ props: { name: string; value: string }[] | undefined,
46
+ value: boolean,
47
+ ): { name: string; value: string }[] {
48
+ const rest = (props ?? []).filter((p) => p.name !== HNDL_PROP);
49
+ return [...rest, { name: HNDL_PROP, value: String(value) }];
50
+ }
51
+
35
52
  /** Union + dedup occurrences by `location`, sorted deterministically. */
36
53
  function mergeOccurrences(a: Occurrence[], b: Occurrence[]): Occurrence[] {
37
54
  const byLoc = new Map<string, Occurrence>();
@@ -69,23 +86,24 @@ export function mergeCboms(boms: readonly CycloneDxBom[]): CycloneDxBom {
69
86
  const root = (bom.metadata as { component?: { name?: string } })?.component?.name;
70
87
  if (typeof root === "string" && root && !roots.includes(root)) roots.push(root);
71
88
 
72
- for (const c of bom.components) {
89
+ // `components` is optional in the CycloneDX 1.6 spec — a legal CBOM can carry none
90
+ // (a scan that found nothing). Treat a missing array as empty instead of crashing.
91
+ for (const c of bom.components ?? []) {
73
92
  const ref = c["bom-ref"];
74
93
  const existing = byRef.get(ref);
75
94
  if (!existing) {
76
- // Deep-ish copy so we can mutate evidence/hndl without touching the input.
95
+ // Deep-ish copy so we can mutate evidence/properties without touching the input.
77
96
  byRef.set(ref, {
78
97
  ...c,
79
98
  cryptoProperties: { ...c.cryptoProperties },
99
+ properties: c.properties ? [...c.properties] : undefined,
80
100
  evidence: { occurrences: occurrencesOf(c) },
81
101
  });
82
102
  } else {
83
103
  const merged = mergeOccurrences(occurrencesOf(existing), occurrencesOf(c));
84
104
  existing.evidence = { occurrences: merged };
85
- existing.cryptoProperties = {
86
- ...existing.cryptoProperties,
87
- harvestNowDecryptLater: hndlOf(existing) || hndlOf(c),
88
- };
105
+ // OR the harvest-now-decrypt-later flag across the merged copies.
106
+ existing.properties = withHndl(existing.properties, hndlOf(existing) || hndlOf(c));
89
107
  }
90
108
  }
91
109
  }
@@ -94,7 +112,19 @@ export function mergeCboms(boms: readonly CycloneDxBom[]): CycloneDxBom {
94
112
  a["bom-ref"] < b["bom-ref"] ? -1 : a["bom-ref"] > b["bom-ref"] ? 1 : 0,
95
113
  );
96
114
 
97
- const serialSeed = components.map((c) => c["bom-ref"]).join("|") + `|${roots.join(",")}`;
115
+ // Content-address the serial over bom-refs AND their occurrence locations (+ roots),
116
+ // so two merges that differ only in occurrence evidence get distinct serials — a
117
+ // CycloneDX serialNumber is meant to identify a BOM *instance*, and downstream
118
+ // bom-link/dedup tooling relies on that. Occurrences are already sorted.
119
+ const serialSeed =
120
+ components
121
+ .map(
122
+ (c) =>
123
+ `${c["bom-ref"]}#${occurrencesOf(c)
124
+ .map((o) => o.location)
125
+ .join(",")}`,
126
+ )
127
+ .join("|") + `|${roots.join(",")}`;
98
128
  const h = createHash("sha256").update(serialSeed, "utf8").digest("hex");
99
129
  const serial = `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-8${h.slice(17, 20)}-${h.slice(20, 32)}`;
100
130
 
package/src/cbom.ts CHANGED
@@ -5,9 +5,12 @@
5
5
  * for compliance / supply-chain tooling.
6
6
  *
7
7
  * Reference: CycloneDX 1.6 cryptography properties
8
- * (https://cyclonedx.org/capabilities/cbom/). We emit one
9
- * `cryptographic-asset` component per distinct (algorithm, primitive) pair
10
- * observed, with occurrence evidence pointing back at the findings.
8
+ * (https://cyclonedx.org/capabilities/cbom/). Each finding is classified into
9
+ * its CycloneDX `assetType` `algorithm` (usage), `certificate` (X.509),
10
+ * `related-crypto-material` (private/public key material), or `protocol` (TLS)
11
+ * and we emit one `cryptographic-asset` component per distinct
12
+ * (assetType, algorithm, discriminator), with occurrence evidence pointing back
13
+ * at the findings. Every asset carries the quantum posture flags.
11
14
  */
12
15
  import { createHash } from "node:crypto";
13
16
 
@@ -30,10 +33,12 @@ export interface CbomComponent {
30
33
  "bom-ref": string;
31
34
  name: string;
32
35
  cryptoProperties: Record<string, unknown>;
36
+ /** CycloneDX component name/value properties (carries the quantum posture flags). */
37
+ properties?: { name: string; value: string }[];
33
38
  evidence?: Record<string, unknown>;
34
39
  }
35
40
 
36
- /** CycloneDX cryptographic primitive for a finding category. */
41
+ /** CycloneDX cryptographic primitive for a finding category (algorithm assets only). */
37
42
  function primitiveFor(category: FindingCategory): string {
38
43
  switch (category) {
39
44
  case "kem":
@@ -42,18 +47,73 @@ function primitiveFor(category: FindingCategory): string {
42
47
  return "key-agree";
43
48
  case "signature":
44
49
  return "signature";
45
- case "certificate":
46
- // "pki" is NOT a valid CycloneDX 1.6 algorithmProperties.primitive enum
47
- // value; use "other" so the CBOM validates (audit: quantum #3). Modeling
48
- // certificates as assetType:"certificate" is a future refinement.
49
- return "other";
50
- case "tls":
51
- return "other";
50
+ case "hash":
51
+ return "hash";
52
52
  default:
53
+ // `certificate` / `tls` no longer route here (they become their own
54
+ // assetType — see {@link classifyAsset}); `dependency` / `rng` and any
55
+ // future category fall back to the valid "other" primitive.
53
56
  return "other";
54
57
  }
55
58
  }
56
59
 
60
+ /** The CycloneDX 1.6 `cryptoProperties.assetType` a finding maps to. */
61
+ type CbomAssetType = "algorithm" | "certificate" | "protocol" | "related-crypto-material";
62
+
63
+ /**
64
+ * Classify a finding into its CycloneDX 1.6 asset type. Most findings are
65
+ * algorithm USAGE (`kem` / `key-exchange` / `signature` / `hash` / …). The
66
+ * `certificate` category is a mix of real X.509 certificates and raw key
67
+ * material, disambiguated by rule id; `tls` findings are protocol configuration.
68
+ *
69
+ * `discriminator` keeps distinct kinds in separate components (it is the algorithm
70
+ * primitive for `algorithm`, the material type for `related-crypto-material`, the
71
+ * protocol type for `protocol`, and empty for `certificate`).
72
+ */
73
+ function classifyAsset(f: Finding): {
74
+ assetType: CbomAssetType;
75
+ discriminator: string;
76
+ materialType?: string;
77
+ protocolType?: string;
78
+ } {
79
+ if (f.category === "tls") {
80
+ return { assetType: "protocol", discriminator: "tls", protocolType: "tls" };
81
+ }
82
+ if (f.category === "certificate") {
83
+ const id = f.ruleId.toLowerCase();
84
+ // Route the explicitly key-SHAPED material to related-crypto-material…
85
+ if (id.includes("private-key") || id.includes("keystore")) {
86
+ return {
87
+ assetType: "related-crypto-material",
88
+ discriminator: "private-key",
89
+ materialType: "private-key",
90
+ };
91
+ }
92
+ if (id.includes("public-key")) {
93
+ return {
94
+ assetType: "related-crypto-material",
95
+ discriminator: "public-key",
96
+ materialType: "public-key",
97
+ };
98
+ }
99
+ if (id.includes("message")) {
100
+ return {
101
+ assetType: "related-crypto-material",
102
+ discriminator: "ciphertext",
103
+ materialType: "ciphertext",
104
+ };
105
+ }
106
+ // …and DEFAULT the rest of the `certificate` category to assetType
107
+ // "certificate" — the category's own meaning. This covers real X.509 certs
108
+ // and CSRs (pem-certificate/pem-cert-request) plus PKI trust material whose
109
+ // ids don't spell "cert": ACM certs (cfn-acm-*), Vault PKI (vault-pki-*),
110
+ // mesh identity, and SPIFFE X.509-SVIDs (spire-*). Previously these fell
111
+ // through to related-crypto-material "key", mislabelling certificates.
112
+ return { assetType: "certificate", discriminator: "" };
113
+ }
114
+ return { assetType: "algorithm", discriminator: primitiveFor(f.category) };
115
+ }
116
+
57
117
  /**
58
118
  * Every CBOM asset here is derived from a quantakrypto finding, and the detectors
59
119
  * only ever fire on classical (Shor-broken) public-key crypto — so an asset is
@@ -102,19 +162,28 @@ function bomRef(key: string): string {
102
162
  * finding. Output is deterministic (components and occurrences are sorted).
103
163
  */
104
164
  export function toCbom(result: ScanResult): CycloneDxBom {
105
- // Group findings by (algorithm | primitive).
165
+ // Group findings by (assetType | algorithm | discriminator) so each distinct
166
+ // cryptographic asset — an algorithm usage, a certificate, key material, or a
167
+ // protocol — becomes its own component.
106
168
  const groups = new Map<
107
169
  string,
108
- { algorithm: AlgorithmFamily; primitive: string; findings: Finding[] }
170
+ {
171
+ assetType: CbomAssetType;
172
+ algorithm: AlgorithmFamily;
173
+ discriminator: string;
174
+ materialType?: string;
175
+ protocolType?: string;
176
+ findings: Finding[];
177
+ }
109
178
  >();
110
179
 
111
180
  for (const f of result.findings) {
112
181
  const algorithm: AlgorithmFamily = f.algorithm ?? "unknown";
113
- const primitive = primitiveFor(f.category);
114
- const key = `${algorithm}|${primitive}`;
182
+ const cls = classifyAsset(f);
183
+ const key = `${cls.assetType}|${algorithm}|${cls.discriminator}`;
115
184
  let g = groups.get(key);
116
185
  if (!g) {
117
- g = { algorithm, primitive, findings: [] };
186
+ g = { ...cls, algorithm, findings: [] };
118
187
  groups.set(key, g);
119
188
  }
120
189
  g.findings.push(f);
@@ -132,30 +201,69 @@ export function toCbom(result: ScanResult): CycloneDxBom {
132
201
 
133
202
  const anyHndl = g.findings.some((f) => f.hndl);
134
203
 
204
+ // The type-specific CycloneDX properties block + a human label for the name.
205
+ let typeProps: Record<string, unknown>;
206
+ let label: string;
207
+ switch (g.assetType) {
208
+ case "certificate":
209
+ // A certificate / CSR: we know the public-key family but not the X.509
210
+ // fields (subject, validity, refs) from a lexical scan, so the block is
211
+ // left minimal — all certificateProperties are optional in 1.6.
212
+ typeProps = { certificateProperties: {} };
213
+ label = "certificate";
214
+ break;
215
+ case "related-crypto-material":
216
+ typeProps = {
217
+ relatedCryptoMaterialProperties: { type: g.materialType ?? "key" },
218
+ };
219
+ label = g.materialType ?? "key";
220
+ break;
221
+ case "protocol":
222
+ typeProps = { protocolProperties: { type: g.protocolType ?? "tls" } };
223
+ label = g.protocolType ?? "tls";
224
+ break;
225
+ case "algorithm":
226
+ default:
227
+ typeProps = {
228
+ algorithmProperties: {
229
+ primitive: g.discriminator,
230
+ parameterSetIdentifier: g.algorithm,
231
+ executionEnvironment: "software-plain-ram",
232
+ classicalSecurityLevel: classicalSecurityLevelFor(g.algorithm),
233
+ nistQuantumSecurityLevel: 0,
234
+ cryptoFunctions:
235
+ g.discriminator === "signature"
236
+ ? ["sign", "verify"]
237
+ : g.discriminator === "kem"
238
+ ? ["encapsulate", "decapsulate"]
239
+ : // CycloneDX 1.6 has no "keyagree" cryptoFunction; "other" is
240
+ // the valid value for a key-agreement primitive.
241
+ ["other"],
242
+ },
243
+ };
244
+ label = g.discriminator;
245
+ break;
246
+ }
247
+
135
248
  return {
136
249
  type: "cryptographic-asset" as const,
137
250
  "bom-ref": bomRef(key),
138
- name: `${g.algorithm} (${g.primitive})`,
251
+ name: `${g.algorithm} (${label})`,
139
252
  cryptoProperties: {
140
- assetType: "algorithm",
141
- algorithmProperties: {
142
- primitive: g.primitive,
143
- parameterSetIdentifier: g.algorithm,
144
- executionEnvironment: "software-plain-ram",
145
- classicalSecurityLevel: classicalSecurityLevelFor(g.algorithm),
146
- nistQuantumSecurityLevel: 0,
147
- cryptoFunctions:
148
- g.primitive === "signature"
149
- ? ["sign", "verify"]
150
- : g.primitive === "kem"
151
- ? ["encapsulate", "decapsulate"]
152
- : g.primitive === "key-agree"
153
- ? ["keyagree"]
154
- : ["other"],
155
- },
156
- quantumVulnerable: isQuantumVulnerable(g.algorithm),
157
- harvestNowDecryptLater: anyHndl,
253
+ assetType: g.assetType,
254
+ ...typeProps,
158
255
  },
256
+ // The quantum posture flags are carried as CycloneDX component `properties`
257
+ // (an open name/value list) rather than inside `cryptoProperties`, whose
258
+ // 1.6 schema is `additionalProperties: false` — so a strict validator
259
+ // accepts the BOM. Namespaced to avoid clashing with other tools' keys.
260
+ properties: [
261
+ {
262
+ name: "quantakrypto:quantumVulnerable",
263
+ value: String(isQuantumVulnerable(g.algorithm)),
264
+ },
265
+ { name: "quantakrypto:harvestNowDecryptLater", value: String(anyHndl) },
266
+ ],
159
267
  evidence: { occurrences },
160
268
  };
161
269
  });
@@ -190,12 +298,18 @@ export function toCbom(result: ScanResult): CycloneDxBom {
190
298
 
191
299
  /**
192
300
  * Derive a stable UUID-shaped serial from the scan result so re-exporting the
193
- * same result yields the same serial number (deterministic output).
301
+ * same result yields the same serial number (deterministic output). Hashed over the
302
+ * actual finding set (ruleId + location per finding), NOT just the COUNT — two scans
303
+ * with the same number of totally different findings must not collide, since a
304
+ * CycloneDX serialNumber identifies a specific BOM instance. Findings are already in
305
+ * a stable order (scan.ts sorts by file/line/ruleId).
194
306
  */
195
307
  function stableUuid(result: ScanResult): string {
196
- const h = createHash("sha256")
197
- .update(`${result.root}|${result.toolVersion}|${result.findings.length}`, "utf8")
198
- .digest("hex");
308
+ const hash = createHash("sha256").update(`${result.root}|${result.toolVersion}`, "utf8");
309
+ for (const f of result.findings) {
310
+ hash.update(`\n${f.ruleId}@${f.location.file}:${f.location.line}:${f.location.column ?? 0}`);
311
+ }
312
+ const h = hash.digest("hex");
199
313
  // Shape as a v4-ish UUID (variant/version nibbles forced).
200
314
  return `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-8${h.slice(17, 20)}-${h.slice(20, 32)}`;
201
315
  }
package/src/comments.ts CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import type { Finding } from "./types.js";
18
18
 
19
- export type CommentStyle = "c" | "hash";
19
+ type CommentStyle = "c" | "hash";
20
20
 
21
21
  /** C-style (line + block) comment languages, by extension. */
22
22
  const C_LIKE: readonly string[] = [
@@ -41,13 +41,32 @@ const C_LIKE: readonly string[] = [
41
41
  ".cxx",
42
42
  ".hpp",
43
43
  ".hh",
44
+ // PHP and Scala also use C-style `//` + `/* */` comments (PHP additionally uses
45
+ // `#`, handled by the hash lexer running first would miss `//`; C-style covers both
46
+ // since PHP `//` is the common form and `#` lines are rare in modern PHP).
47
+ ".php",
48
+ ".php3",
49
+ ".php4",
50
+ ".php5",
51
+ ".phtml",
52
+ ".scala",
53
+ ".sc",
54
+ ".swift",
55
+ // Objective-C (.m/.mm) and Dart (.dart) both use C-style `//` + `/* */`.
56
+ ".m",
57
+ ".mm",
58
+ ".dart",
59
+ // Smart-contract languages (Solidity/Move/Cairo) also use C-style comments.
60
+ ".sol",
61
+ ".move",
62
+ ".cairo",
44
63
  ];
45
64
 
46
65
  /** Hash-style (`#`) comment languages, by extension. */
47
- const HASH_LIKE: readonly string[] = [".py", ".pyi", ".pyw", ".rb"];
66
+ const HASH_LIKE: readonly string[] = [".py", ".pyi", ".pyw", ".rb", ".ex", ".exs"];
48
67
 
49
68
  /** The comment style for a file path, or null when we don't strip comments for it. */
50
- export function commentStyleForFile(file: string): CommentStyle | null {
69
+ function commentStyleForFile(file: string): CommentStyle | null {
51
70
  const lower = file.toLowerCase();
52
71
  if (C_LIKE.some((e) => lower.endsWith(e))) return "c";
53
72
  if (HASH_LIKE.some((e) => lower.endsWith(e))) return "hash";
@@ -149,7 +168,7 @@ export function commentSpans(
149
168
  * exempts `pem-*` rules. Comments and normal strings are skipped so a `"""`
150
169
  * delimiter inside them is not mis-detected.
151
170
  */
152
- export function pythonDocstringSpans(content: string): Array<[number, number]> {
171
+ function pythonDocstringSpans(content: string): Array<[number, number]> {
153
172
  const spans: Array<[number, number]> = [];
154
173
  const n = content.length;
155
174
  let i = 0;
@@ -190,7 +209,7 @@ export function pythonDocstringSpans(content: string): Array<[number, number]> {
190
209
  }
191
210
 
192
211
  /** True if `offset` falls inside one of the (sorted, non-overlapping) spans. */
193
- export function offsetInSpans(spans: ReadonlyArray<[number, number]>, offset: number): boolean {
212
+ function offsetInSpans(spans: ReadonlyArray<[number, number]>, offset: number): boolean {
194
213
  let lo = 0;
195
214
  let hi = spans.length - 1;
196
215
  while (lo <= hi) {
@@ -211,7 +230,7 @@ export function offsetInSpans(spans: ReadonlyArray<[number, number]>, offset: nu
211
230
  * it is language-agnostic. `qscan-ignore-line` is not a substring of
212
231
  * `qscan-ignore-next-line`, so the two never collide.
213
232
  */
214
- export function ignoredLines(content: string): Set<number> {
233
+ function ignoredLines(content: string): Set<number> {
215
234
  const ignored = new Set<number>();
216
235
  const lines = content.split("\n");
217
236
  for (let i = 0; i < lines.length; i++) {