@cdxgen/cdxgen 13.1.0 → 13.3.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 (283) hide show
  1. package/README.md +32 -15
  2. package/bin/cdxgen.js +243 -122
  3. package/bin/evinse.js +7 -0
  4. package/bin/sign.js +88 -14
  5. package/bin/tracebom.js +64 -4
  6. package/bin/validate.js +29 -7
  7. package/bin/verify.js +79 -39
  8. package/data/crypto-oid.json +88 -12
  9. package/data/remediations.json +47 -0
  10. package/data/rules/ai-bom.yaml +78 -0
  11. package/data/rules/cargo-rust.yaml +132 -0
  12. package/data/rules/mcp-servers.yaml +122 -0
  13. package/lib/audit/targets.js +6 -1
  14. package/lib/cli/bomAssembly.js +117 -15
  15. package/lib/cli/cliOptions.js +93 -1
  16. package/lib/cli/index.js +235 -5
  17. package/lib/cli/jsBom.js +108 -26
  18. package/lib/cli/jvmBom.js +68 -12
  19. package/lib/cli/managedBom.js +264 -41
  20. package/lib/cli/nativeBom.js +923 -15
  21. package/lib/core/activity.js +120 -2
  22. package/lib/core/env.js +44 -7
  23. package/lib/core/fs.js +174 -6
  24. package/lib/core/metadataProperties.js +97 -0
  25. package/lib/core/projectConfig.js +31 -4
  26. package/lib/core/userAgent.js +151 -0
  27. package/lib/ecosystems/bunutils.js +269 -101
  28. package/lib/ecosystems/cargoCache.js +364 -0
  29. package/lib/ecosystems/caxa.js +447 -7
  30. package/lib/ecosystems/cmakeResolver.js +66 -0
  31. package/lib/ecosystems/cppEvidence.js +104 -33
  32. package/lib/ecosystems/ecosystems.js +260 -99
  33. package/lib/ecosystems/golem.js +11 -1
  34. package/lib/ecosystems/gradleutils.js +185 -9
  35. package/lib/ecosystems/jsEvidence.js +19 -20
  36. package/lib/ecosystems/kosi.js +1263 -0
  37. package/lib/ecosystems/npmutils.js +110 -9
  38. package/lib/ecosystems/parsers-crystal.js +179 -0
  39. package/lib/ecosystems/parsers-dotnet.js +120 -49
  40. package/lib/ecosystems/parsers-elm.js +816 -0
  41. package/lib/ecosystems/parsers-gleam.js +1 -1
  42. package/lib/ecosystems/parsers-go.js +47 -9
  43. package/lib/ecosystems/parsers-js.js +171 -50
  44. package/lib/ecosystems/parsers-julia.js +268 -0
  45. package/lib/ecosystems/parsers-lua.js +218 -0
  46. package/lib/ecosystems/parsers-misc.js +919 -161
  47. package/lib/ecosystems/parsers-nim.js +221 -0
  48. package/lib/ecosystems/parsers-opam.js +180 -0
  49. package/lib/ecosystems/parsers-perl.js +277 -0
  50. package/lib/ecosystems/parsers-python.js +27 -15
  51. package/lib/ecosystems/parsers-r.js +148 -0
  52. package/lib/ecosystems/parsers-rebar.js +411 -0
  53. package/lib/ecosystems/parsers-rust.js +954 -33
  54. package/lib/ecosystems/parsers-spack.js +204 -0
  55. package/lib/ecosystems/parsers-stack.js +264 -0
  56. package/lib/ecosystems/parsers-terraform.js +194 -0
  57. package/lib/ecosystems/rubyutils.js +1426 -166
  58. package/lib/ecosystems/rusi.js +158 -7
  59. package/lib/evinser/evinser.js +547 -129
  60. package/lib/evinser/swiftsem.js +1914 -302
  61. package/lib/helpers/agenticToolutils.js +925 -0
  62. package/lib/helpers/bomSigner.js +652 -221
  63. package/lib/inventory/agentFormulationParser.js +57 -4
  64. package/lib/inventory/aiCollector.js +504 -10
  65. package/lib/inventory/aiInventory.js +12 -0
  66. package/lib/inventory/analyzer.js +488 -30
  67. package/lib/inventory/astWorker.js +6 -0
  68. package/lib/inventory/atomUtils.js +568 -31
  69. package/lib/inventory/auditCategories.js +8 -0
  70. package/lib/inventory/cbomutils.js +30 -0
  71. package/lib/inventory/cdxrs.js +110 -14
  72. package/lib/inventory/communityAiConfigParser.js +215 -2
  73. package/lib/inventory/depsUtils.js +183 -11
  74. package/lib/inventory/display.js +4 -5
  75. package/lib/inventory/dosai.js +627 -13
  76. package/lib/inventory/dynamic.js +39 -1
  77. package/lib/inventory/envcontext.js +9 -6
  78. package/lib/inventory/evidenceUtils.js +26 -5
  79. package/lib/inventory/fetchBatch.js +190 -19
  80. package/lib/inventory/fetchRate.js +74 -11
  81. package/lib/inventory/forgeEnricher.js +3 -2
  82. package/lib/inventory/jvmToolEnv.js +6 -5
  83. package/lib/inventory/mcpConfigParser.js +166 -2
  84. package/lib/inventory/mcpDiscovery.js +11 -0
  85. package/lib/inventory/mcpServerManifest.js +389 -0
  86. package/lib/inventory/mcpbBundle.js +419 -0
  87. package/lib/inventory/plugins.js +3 -0
  88. package/lib/inventory/protobom.js +62 -89
  89. package/lib/inventory/protobomLoader.js +4 -0
  90. package/lib/inventory/purl.js +152 -3
  91. package/lib/inventory/rustFormulationParser.js +1 -1
  92. package/lib/inventory/sbomDocument.js +2 -70
  93. package/lib/inventory/source.js +47 -23
  94. package/lib/inventory/stylePackageRefs.js +41 -0
  95. package/lib/inventory/svelteUtils.js +524 -0
  96. package/lib/inventory/traceRunner.js +210 -21
  97. package/lib/managers/binary.js +115 -24
  98. package/lib/managers/docker.js +440 -20
  99. package/lib/managers/oci.js +39 -1
  100. package/lib/parsers/cmakeLists.js +452 -0
  101. package/lib/parsers/huggingfaceUtils.js +15 -7
  102. package/lib/parsers/largeJson.js +454 -0
  103. package/lib/parsers/npmrc.js +19 -1
  104. package/lib/parsers/onnx.js +294 -0
  105. package/lib/parsers/safetensors.js +114 -0
  106. package/lib/stages/postgen/introspection/markers.js +29 -6
  107. package/lib/stages/postgen/postgen.js +237 -16
  108. package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +462 -0
  109. package/lib/validator/bomValidator.js +6 -16
  110. package/lib/validator/index.js +48 -10
  111. package/lib/validator/reporters/console.js +3 -0
  112. package/lib/validator/reporters/json.js +1 -0
  113. package/lib/validator/reporters/sarif.js +7 -0
  114. package/package.json +27 -27
  115. package/types/lib/audit/targets.d.ts.map +1 -1
  116. package/types/lib/cli/bomAssembly.d.ts +2 -1
  117. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  118. package/types/lib/cli/cliOptions.d.ts +33 -1
  119. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  120. package/types/lib/cli/index.d.ts +2 -2
  121. package/types/lib/cli/index.d.ts.map +1 -1
  122. package/types/lib/cli/jsBom.d.ts +23 -0
  123. package/types/lib/cli/jsBom.d.ts.map +1 -1
  124. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  125. package/types/lib/cli/managedBom.d.ts +33 -0
  126. package/types/lib/cli/managedBom.d.ts.map +1 -1
  127. package/types/lib/cli/nativeBom.d.ts +88 -8
  128. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  129. package/types/lib/core/activity.d.ts.map +1 -1
  130. package/types/lib/core/env.d.ts +21 -0
  131. package/types/lib/core/env.d.ts.map +1 -1
  132. package/types/lib/core/fs.d.ts +55 -0
  133. package/types/lib/core/fs.d.ts.map +1 -1
  134. package/types/lib/core/metadataProperties.d.ts +39 -0
  135. package/types/lib/core/metadataProperties.d.ts.map +1 -0
  136. package/types/lib/core/projectConfig.d.ts +6 -2
  137. package/types/lib/core/projectConfig.d.ts.map +1 -1
  138. package/types/lib/core/userAgent.d.ts +56 -0
  139. package/types/lib/core/userAgent.d.ts.map +1 -0
  140. package/types/lib/ecosystems/bunutils.d.ts +12 -5
  141. package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
  142. package/types/lib/ecosystems/cargoCache.d.ts +75 -0
  143. package/types/lib/ecosystems/cargoCache.d.ts.map +1 -0
  144. package/types/lib/ecosystems/caxa.d.ts +14 -0
  145. package/types/lib/ecosystems/caxa.d.ts.map +1 -1
  146. package/types/lib/ecosystems/cmakeResolver.d.ts +23 -0
  147. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
  148. package/types/lib/ecosystems/cppEvidence.d.ts +2 -2
  149. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  150. package/types/lib/ecosystems/ecosystems.d.ts +15 -1
  151. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  152. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  153. package/types/lib/ecosystems/gradleutils.d.ts +40 -4
  154. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  155. package/types/lib/ecosystems/jsEvidence.d.ts +5 -2
  156. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  157. package/types/lib/ecosystems/kosi.d.ts +86 -0
  158. package/types/lib/ecosystems/kosi.d.ts.map +1 -0
  159. package/types/lib/ecosystems/npmutils.d.ts +42 -0
  160. package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
  161. package/types/lib/ecosystems/parsers-crystal.d.ts +27 -0
  162. package/types/lib/ecosystems/parsers-crystal.d.ts.map +1 -0
  163. package/types/lib/ecosystems/parsers-dotnet.d.ts +19 -0
  164. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  165. package/types/lib/ecosystems/parsers-elm.d.ts +79 -0
  166. package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -0
  167. package/types/lib/ecosystems/parsers-go.d.ts +10 -0
  168. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  169. package/types/lib/ecosystems/parsers-js.d.ts +10 -4
  170. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  171. package/types/lib/ecosystems/parsers-julia.d.ts +57 -0
  172. package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -0
  173. package/types/lib/ecosystems/parsers-lua.d.ts +50 -0
  174. package/types/lib/ecosystems/parsers-lua.d.ts.map +1 -0
  175. package/types/lib/ecosystems/parsers-misc.d.ts +90 -3
  176. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  177. package/types/lib/ecosystems/parsers-nim.d.ts +43 -0
  178. package/types/lib/ecosystems/parsers-nim.d.ts.map +1 -0
  179. package/types/lib/ecosystems/parsers-opam.d.ts +31 -0
  180. package/types/lib/ecosystems/parsers-opam.d.ts.map +1 -0
  181. package/types/lib/ecosystems/parsers-perl.d.ts +36 -0
  182. package/types/lib/ecosystems/parsers-perl.d.ts.map +1 -0
  183. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  184. package/types/lib/ecosystems/parsers-r.d.ts +35 -0
  185. package/types/lib/ecosystems/parsers-r.d.ts.map +1 -0
  186. package/types/lib/ecosystems/parsers-rebar.d.ts +42 -0
  187. package/types/lib/ecosystems/parsers-rebar.d.ts.map +1 -0
  188. package/types/lib/ecosystems/parsers-rust.d.ts +199 -0
  189. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  190. package/types/lib/ecosystems/parsers-spack.d.ts +33 -0
  191. package/types/lib/ecosystems/parsers-spack.d.ts.map +1 -0
  192. package/types/lib/ecosystems/parsers-stack.d.ts +35 -0
  193. package/types/lib/ecosystems/parsers-stack.d.ts.map +1 -0
  194. package/types/lib/ecosystems/parsers-terraform.d.ts +34 -0
  195. package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -0
  196. package/types/lib/ecosystems/pythonutils.d.ts +1 -1
  197. package/types/lib/ecosystems/rubyutils.d.ts +143 -2
  198. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  199. package/types/lib/ecosystems/rusi.d.ts +13 -0
  200. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  201. package/types/lib/evinser/evinser.d.ts +81 -2
  202. package/types/lib/evinser/evinser.d.ts.map +1 -1
  203. package/types/lib/evinser/swiftsem.d.ts +280 -15
  204. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  205. package/types/lib/helpers/agenticToolutils.d.ts +87 -0
  206. package/types/lib/helpers/agenticToolutils.d.ts.map +1 -0
  207. package/types/lib/helpers/bomSigner.d.ts +106 -13
  208. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  209. package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -1
  210. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  211. package/types/lib/inventory/aiInventory.d.ts.map +1 -1
  212. package/types/lib/inventory/analyzer.d.ts.map +1 -1
  213. package/types/lib/inventory/atomUtils.d.ts +145 -3
  214. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  215. package/types/lib/inventory/auditCategories.d.ts +4 -0
  216. package/types/lib/inventory/auditCategories.d.ts.map +1 -1
  217. package/types/lib/inventory/cbomutils.d.ts.map +1 -1
  218. package/types/lib/inventory/cdxrs.d.ts +8 -3
  219. package/types/lib/inventory/cdxrs.d.ts.map +1 -1
  220. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  221. package/types/lib/inventory/depsUtils.d.ts +15 -0
  222. package/types/lib/inventory/depsUtils.d.ts.map +1 -1
  223. package/types/lib/inventory/display.d.ts.map +1 -1
  224. package/types/lib/inventory/dosai.d.ts +87 -1
  225. package/types/lib/inventory/dosai.d.ts.map +1 -1
  226. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  227. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  228. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  229. package/types/lib/inventory/fetchBatch.d.ts +34 -0
  230. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  231. package/types/lib/inventory/fetchRate.d.ts +9 -6
  232. package/types/lib/inventory/fetchRate.d.ts.map +1 -1
  233. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
  234. package/types/lib/inventory/jvmToolEnv.d.ts +5 -4
  235. package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
  236. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  237. package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -1
  238. package/types/lib/inventory/mcpServerManifest.d.ts +19 -0
  239. package/types/lib/inventory/mcpServerManifest.d.ts.map +1 -0
  240. package/types/lib/inventory/mcpbBundle.d.ts +19 -0
  241. package/types/lib/inventory/mcpbBundle.d.ts.map +1 -0
  242. package/types/lib/inventory/plugins.d.ts.map +1 -1
  243. package/types/lib/inventory/protobom.d.ts +18 -13
  244. package/types/lib/inventory/protobom.d.ts.map +1 -1
  245. package/types/lib/inventory/protobomLoader.d.ts.map +1 -1
  246. package/types/lib/inventory/purl.d.ts +71 -2
  247. package/types/lib/inventory/purl.d.ts.map +1 -1
  248. package/types/lib/inventory/sbomDocument.d.ts.map +1 -1
  249. package/types/lib/inventory/source.d.ts.map +1 -1
  250. package/types/lib/inventory/stylePackageRefs.d.ts +17 -0
  251. package/types/lib/inventory/stylePackageRefs.d.ts.map +1 -0
  252. package/types/lib/inventory/svelteUtils.d.ts +124 -0
  253. package/types/lib/inventory/svelteUtils.d.ts.map +1 -0
  254. package/types/lib/inventory/traceRunner.d.ts +47 -1
  255. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  256. package/types/lib/managers/binary.d.ts +30 -1
  257. package/types/lib/managers/binary.d.ts.map +1 -1
  258. package/types/lib/managers/docker.d.ts +29 -0
  259. package/types/lib/managers/docker.d.ts.map +1 -1
  260. package/types/lib/managers/oci.d.ts +14 -0
  261. package/types/lib/managers/oci.d.ts.map +1 -1
  262. package/types/lib/parsers/cmakeLists.d.ts +76 -0
  263. package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
  264. package/types/lib/parsers/huggingfaceUtils.d.ts +8 -1
  265. package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
  266. package/types/lib/parsers/largeJson.d.ts +52 -0
  267. package/types/lib/parsers/largeJson.d.ts.map +1 -0
  268. package/types/lib/parsers/npmrc.d.ts +5 -0
  269. package/types/lib/parsers/npmrc.d.ts.map +1 -1
  270. package/types/lib/parsers/onnx.d.ts +28 -0
  271. package/types/lib/parsers/onnx.d.ts.map +1 -0
  272. package/types/lib/parsers/safetensors.d.ts +22 -0
  273. package/types/lib/parsers/safetensors.d.ts.map +1 -0
  274. package/types/lib/stages/postgen/introspection/markers.d.ts +3 -2
  275. package/types/lib/stages/postgen/introspection/markers.d.ts.map +1 -1
  276. package/types/lib/stages/postgen/postgen.d.ts +33 -0
  277. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  278. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  279. package/types/lib/validator/index.d.ts +10 -1
  280. package/types/lib/validator/index.d.ts.map +1 -1
  281. package/types/lib/validator/reporters/console.d.ts.map +1 -1
  282. package/types/lib/validator/reporters/json.d.ts.map +1 -1
  283. package/types/lib/validator/reporters/sarif.d.ts.map +1 -1
@@ -15,6 +15,10 @@ import { join, resolve } from "node:path";
15
15
 
16
16
  import { isSecureMode, readEnvironmentVariable } from "../core/activity.js";
17
17
  import { PROJECT_TYPE_ALIASES } from "../core/env.js";
18
+ import {
19
+ METADATA_PROPERTY_CONFIG_KEYS,
20
+ parseMetadataProperties,
21
+ } from "../core/metadataProperties.js";
18
22
  import {
19
23
  DEFAULT_CDX_SPEC_VERSION,
20
24
  normalizeCycloneDxComponentTypeFilter,
@@ -120,6 +124,80 @@ export function isUserProvided(value, yaDefault) {
120
124
  return value !== undefined && value !== yaDefault;
121
125
  }
122
126
 
127
+ /**
128
+ * Combine the custom metadata properties of every source (discussion 4391):
129
+ * the `--metadata-property` flag, the CDXGEN_METADATA_PROPERTY and
130
+ * CDXGEN_METADATA_PROPERTIES environment variables, and a config file's
131
+ * `metadata-property` or `metadataProperties` entry.
132
+ *
133
+ * yargs would let the highest-precedence source replace the others outright,
134
+ * so each is read on its own and they are merged instead. A name set by more
135
+ * than one source takes its values from the one that wins in the usual order
136
+ * — the command line, then the environment, then the config file — while a
137
+ * source may repeat a name for a multi-valued property.
138
+ *
139
+ * @param {object} args Parsed yargs argv
140
+ * @param {object} [context]
141
+ * @param {string[]} [context.argv] Raw command-line arguments, which tell a
142
+ * flag on the command line from one yargs filled in from elsewhere
143
+ * @param {object} [context.projectConfig] The sanitized config file contents.
144
+ * Without it, a programmatic caller's `args` are taken as the config.
145
+ * @returns {{name: string, value: string}[]} The merged properties
146
+ */
147
+ export function resolveMetadataProperties(
148
+ args,
149
+ { argv = process.argv, projectConfig } = {},
150
+ ) {
151
+ const flagGiven = argv.some((argument) =>
152
+ ["--metadata-property", "--metadataProperty"].includes(
153
+ `${argument}`.split("=")[0],
154
+ ),
155
+ );
156
+ const fromConfig = projectConfig
157
+ ? METADATA_PROPERTY_CONFIG_KEYS.flatMap((key) =>
158
+ parseMetadataProperties(projectConfig[key]),
159
+ )
160
+ : flagGiven
161
+ ? []
162
+ : [
163
+ ...parseMetadataProperties(args?.metadataProperty),
164
+ ...parseMetadataProperties(args?.metadataProperties),
165
+ ];
166
+ const sources = [
167
+ flagGiven ? parseMetadataProperties(args?.metadataProperty) : [],
168
+ [
169
+ ...parseMetadataProperties(
170
+ readEnvironmentVariable("CDXGEN_METADATA_PROPERTY"),
171
+ ),
172
+ ...parseMetadataProperties(
173
+ readEnvironmentVariable("CDXGEN_METADATA_PROPERTIES"),
174
+ ),
175
+ ],
176
+ fromConfig,
177
+ ];
178
+ const properties = [];
179
+ const claimedNames = new Set();
180
+ for (const source of sources) {
181
+ const sourceNames = new Set();
182
+ for (const aprop of source) {
183
+ if (
184
+ claimedNames.has(aprop.name) ||
185
+ properties.some(
186
+ (prop) => prop.name === aprop.name && prop.value === aprop.value,
187
+ )
188
+ ) {
189
+ continue;
190
+ }
191
+ properties.push(aprop);
192
+ sourceNames.add(aprop.name);
193
+ }
194
+ for (const name of sourceNames) {
195
+ claimedNames.add(name);
196
+ }
197
+ }
198
+ return properties;
199
+ }
200
+
123
201
  /**
124
202
  * Apply command-name-based defaults to the raw parsed args. When cdxgen is
125
203
  * invoked via a symlink or alias (e.g. `obom`, `cbom`, `spdxgen`, `aibom`),
@@ -162,6 +240,8 @@ export function applyCommandNameDefaults(args, invokedCommandName) {
162
240
  * @param {object} context
163
241
  * @param {string} context.filePath Resolved source path
164
242
  * @param {boolean} context.isRemoteOrPurl True when source is a URL or purl
243
+ * @param {string[]} [context.argv] Raw command-line arguments
244
+ * @param {object} [context.projectConfig] Sanitized config file contents
165
245
  * @returns {object} The initial options object
166
246
  */
167
247
  /**
@@ -221,8 +301,12 @@ function resolveIntrospectOption(args, argv) {
221
301
 
222
302
  export function buildInitialOptions(
223
303
  args,
224
- { filePath, isRemoteOrPurl, argv = process.argv },
304
+ { filePath, isRemoteOrPurl, argv = process.argv, projectConfig },
225
305
  ) {
306
+ const metadataProperties = resolveMetadataProperties(args, {
307
+ argv,
308
+ projectConfig,
309
+ });
226
310
  const res = Object.assign({}, args, {
227
311
  projectType: args.type,
228
312
  multiProject: args.recurse,
@@ -235,6 +319,9 @@ export function buildInitialOptions(
235
319
  include: args.include || args.includeRegex,
236
320
  noIgnore: args.noIgnore,
237
321
  gitAiNotesRef: args.gitAiNotesRef || "refs/notes/ai",
322
+ metadataProperties: metadataProperties.length
323
+ ? metadataProperties
324
+ : undefined,
238
325
  // Introspection: the flag or the documented environment opt-in. An
239
326
  // explicit --no-introspect stays `false` and beats both, while an
240
327
  // unmentioned flag stays undefined so a profile can still enable it.
@@ -598,6 +685,9 @@ export function applyAdvancedOptions(options, context = {}) {
598
685
  * passed `--spec-version`
599
686
  * @param {boolean} [context.isDryRun=false] Dry-run mode
600
687
  * @param {boolean} [context.isSecureMode] Secure mode
688
+ * @param {object} [context.projectConfig] Sanitized config file contents,
689
+ * whose metadata properties merge
690
+ * with the other sources'
601
691
  * @returns {{ options: object, warnings: OptionsWarning[] }}
602
692
  */
603
693
  export function buildOptionsFromArgs(args, context) {
@@ -607,12 +697,14 @@ export function buildOptionsFromArgs(args, context) {
607
697
  isRemoteOrPurl,
608
698
  userSetSpecVersion,
609
699
  isDryRun = false,
700
+ projectConfig,
610
701
  } = context;
611
702
 
612
703
  const expandedArgs = applyCommandNameDefaults(args, invokedCommandName);
613
704
  const options = buildInitialOptions(expandedArgs, {
614
705
  filePath,
615
706
  isRemoteOrPurl,
707
+ projectConfig,
616
708
  });
617
709
  const phase3Warnings = applyPostConstructionOverrides(options, {
618
710
  invokedCommandName,
package/lib/cli/index.js CHANGED
@@ -32,6 +32,11 @@ import { thoughtLog } from "../core/logger.js";
32
32
  import { mapWithConcurrency } from "../core/parallel.js";
33
33
  import { dirNameStr } from "../core/paths.js";
34
34
  import { ui } from "../core/ui.js";
35
+ import { isElmProjectFile } from "../ecosystems/parsers-elm.js";
36
+ import {
37
+ isJuliaManifestFile,
38
+ isJuliaProjectFile,
39
+ } from "../ecosystems/parsers-julia.js";
35
40
  import {
36
41
  parseBitbucketPipelinesFile,
37
42
  parseContainerFile,
@@ -79,6 +84,7 @@ import {
79
84
  exportArchive,
80
85
  exportImage,
81
86
  getPkgPathList,
87
+ isImageReference,
82
88
  parseImageName,
83
89
  } from "../managers/docker.js";
84
90
  import {
@@ -90,6 +96,7 @@ import {
90
96
  determineParentComponent,
91
97
  } from "./bomAssembly.js";
92
98
  import {
99
+ createAgenticBom,
93
100
  createAsarBom,
94
101
  createCaxaBom,
95
102
  createChromeExtensionBom,
@@ -126,24 +133,36 @@ import {
126
133
  createGitHubBom,
127
134
  createHelmBom,
128
135
  createJenkinsBom,
136
+ createPerlBom,
129
137
  createPHPBom,
130
138
  createPythonBom,
139
+ createRBom,
131
140
  createRubyBom,
141
+ createTerraformBom,
132
142
  } from "./managedBom.js";
133
143
  import {
134
144
  createCargoCacheBom,
135
145
  createClojureBom,
136
146
  createCocoaBom,
137
147
  createCppBom,
148
+ createCrystalBom,
138
149
  createDartBom,
139
150
  createElixirBom,
151
+ createElmBom,
152
+ createErlangBom,
140
153
  createGleamBom,
141
154
  createGoBom,
142
155
  createHaskellBom,
156
+ createJuliaBom,
157
+ createLuaBom,
158
+ createNimBom,
143
159
  createNixBom,
160
+ createOCamlBom,
144
161
  createRustBom,
162
+ createSpackBom,
145
163
  createSwiftBom,
146
164
  createZigBom,
165
+ findStackLockFiles,
147
166
  getCargoCacheDir,
148
167
  } from "./nativeBom.js";
149
168
 
@@ -154,22 +173,33 @@ export {
154
173
  createGitHubBom,
155
174
  createHelmBom,
156
175
  createJenkinsBom,
176
+ createPerlBom,
157
177
  createPHPBom,
158
178
  createPixiBom,
159
179
  createPythonBom,
180
+ createRBom,
160
181
  createRubyBom,
182
+ createTerraformBom,
161
183
  } from "./managedBom.js";
162
184
  export {
163
185
  createClojureBom,
164
186
  createCocoaBom,
165
187
  createCppBom,
188
+ createCrystalBom,
166
189
  createDartBom,
167
190
  createElixirBom,
191
+ createElmBom,
192
+ createErlangBom,
168
193
  createGleamBom,
169
194
  createGoBom,
170
195
  createHaskellBom,
196
+ createJuliaBom,
197
+ createLuaBom,
198
+ createNimBom,
171
199
  createNixBom,
200
+ createOCamlBom,
172
201
  createRustBom,
202
+ createSpackBom,
173
203
  createSwiftBom,
174
204
  createZigBom,
175
205
  } from "./nativeBom.js";
@@ -1871,17 +1901,49 @@ export async function createDynamicBom(path, options) {
1871
1901
  blockExec: options.traceBlockExec,
1872
1902
  traceCrypto: options.traceCrypto,
1873
1903
  cbom: options.cbom,
1904
+ proxyEgress: options.traceProxyEgress,
1905
+ allowLoopback: options.traceAllowLoopback,
1906
+ dryRun: options.traceDryRun,
1907
+ policy: options.tracePolicy,
1908
+ policyFile: options.tracePolicyFile,
1909
+ blockInterpreters: options.traceBlockInterpreters,
1910
+ denyPersistenceWrites: options.traceDenyPersistenceWrites,
1911
+ privateTmp: options.tracePrivateTmp,
1912
+ protectHome: options.traceProtectHome,
1874
1913
  };
1875
1914
 
1876
- const { components: pkgList, services: traceServices } =
1877
- await buildDynamicComponents(commandStr, workingDir, traceOptions);
1915
+ const {
1916
+ components: pkgList,
1917
+ services: traceServices,
1918
+ dryRunSummary,
1919
+ } = await buildDynamicComponents(commandStr, workingDir, traceOptions);
1878
1920
 
1879
- return buildBomNSData(options, pkgList, "generic", {
1921
+ const bomNSData = buildBomNSData(options, pkgList, "generic", {
1880
1922
  src: workingDir,
1881
1923
  projectType: "dynamic",
1882
1924
  filename: commandStr,
1883
1925
  services: traceServices,
1884
1926
  });
1927
+ // A dry run denies every side effect, so the attempted-operation counts are
1928
+ // the result. Only counts are recorded, never the paths or targets.
1929
+ if (dryRunSummary && bomNSData?.bomJson?.metadata) {
1930
+ const metadata = bomNSData.bomJson.metadata;
1931
+ metadata.properties = metadata.properties || [];
1932
+ metadata.properties.push({ name: "cdx:dynamic:dryRun", value: "true" });
1933
+ metadata.properties.push({
1934
+ name: "cdx:dynamic:dryRun:captured",
1935
+ value: dryRunSummary.captured === false ? "false" : "true",
1936
+ });
1937
+ for (const [key, value] of Object.entries(dryRunSummary)) {
1938
+ if (Number.isInteger(value)) {
1939
+ metadata.properties.push({
1940
+ name: `cdx:dynamic:dryRun:${key}`,
1941
+ value: String(value),
1942
+ });
1943
+ }
1944
+ }
1945
+ }
1946
+ return bomNSData;
1885
1947
  }
1886
1948
 
1887
1949
  /**
@@ -2060,7 +2122,8 @@ export async function createXBom(path, options) {
2060
2122
  `${options.multiProject ? "**/" : ""}cabal.project.freeze`,
2061
2123
  options,
2062
2124
  );
2063
- if (hackageFiles.length) {
2125
+ const stackLockDetectFiles = findStackLockFiles(path, options);
2126
+ if (hackageFiles.length || stackLockDetectFiles.length) {
2064
2127
  return createHaskellBom(path, options);
2065
2128
  }
2066
2129
 
@@ -2285,6 +2348,131 @@ export async function createXBom(path, options) {
2285
2348
  if (gleamTomlFiles.length) {
2286
2349
  return await createGleamBom(path, options);
2287
2350
  }
2351
+
2352
+ // Julia
2353
+ const juliaProjectFiles = getAllFiles(
2354
+ path,
2355
+ `${options.multiProject ? "**/" : ""}Project.toml`,
2356
+ options,
2357
+ );
2358
+ const juliaManifestFiles = getAllFiles(
2359
+ path,
2360
+ `${options.multiProject ? "**/" : ""}Manifest.toml`,
2361
+ options,
2362
+ );
2363
+ // `Project.toml` is not a name Julia owns — Cloud Native Buildpacks use it
2364
+ // too — so dispatch only when a file actually declares a Julia environment.
2365
+ if (
2366
+ juliaManifestFiles.some(isJuliaManifestFile) ||
2367
+ juliaProjectFiles.some(isJuliaProjectFile)
2368
+ ) {
2369
+ return await createJuliaBom(path, options);
2370
+ }
2371
+
2372
+ // Erlang with rebar3
2373
+ const rebarLockFiles = getAllFiles(
2374
+ path,
2375
+ `${options.multiProject ? "**/" : ""}rebar.lock`,
2376
+ options,
2377
+ );
2378
+ if (rebarLockFiles.length) {
2379
+ return await createErlangBom(path, options);
2380
+ }
2381
+
2382
+ // OCaml with opam
2383
+ const opamLockedFiles = getAllFiles(
2384
+ path,
2385
+ `${options.multiProject ? "**/" : ""}*.opam.locked`,
2386
+ options,
2387
+ );
2388
+ if (opamLockedFiles.length) {
2389
+ return await createOCamlBom(path, options);
2390
+ }
2391
+
2392
+ // Elm with elm.json (0.19) or elm-package.json (0.18)
2393
+ const elmJsonFiles = getAllFiles(
2394
+ path,
2395
+ `${options.multiProject ? "**/" : ""}elm.json`,
2396
+ options,
2397
+ ).filter(isElmProjectFile);
2398
+ const legacyElmFiles = getAllFiles(
2399
+ path,
2400
+ `${options.multiProject ? "**/" : ""}elm-package.json`,
2401
+ options,
2402
+ );
2403
+ if (elmJsonFiles.length || legacyElmFiles.length) {
2404
+ return await createElmBom(path, options);
2405
+ }
2406
+
2407
+ // Crystal with shards
2408
+ const shardYmlFiles = getAllFiles(
2409
+ path,
2410
+ `${options.multiProject ? "**/" : ""}shard.yml`,
2411
+ options,
2412
+ );
2413
+ if (shardYmlFiles.length) {
2414
+ return await createCrystalBom(path, options);
2415
+ }
2416
+
2417
+ // Nim with nimble
2418
+ const nimbleFiles = getAllFiles(
2419
+ path,
2420
+ `${options.multiProject ? "**/" : ""}*.nimble`,
2421
+ options,
2422
+ );
2423
+ if (nimbleFiles.length) {
2424
+ return await createNimBom(path, options);
2425
+ }
2426
+
2427
+ // Lua with LuaRocks
2428
+ const rockspecFiles = getAllFiles(
2429
+ path,
2430
+ `${options.multiProject ? "**/" : ""}*.rockspec`,
2431
+ options,
2432
+ );
2433
+ if (rockspecFiles.length) {
2434
+ return await createLuaBom(path, options);
2435
+ }
2436
+
2437
+ // Spack environments
2438
+ const spackLockFiles = getAllFiles(
2439
+ path,
2440
+ `${options.multiProject ? "**/" : ""}spack.lock`,
2441
+ options,
2442
+ );
2443
+ if (spackLockFiles.length) {
2444
+ return await createSpackBom(path, options);
2445
+ }
2446
+
2447
+ // R with renv
2448
+ const renvLockFiles = getAllFiles(
2449
+ path,
2450
+ `${options.multiProject ? "**/" : ""}renv.lock`,
2451
+ options,
2452
+ );
2453
+ if (renvLockFiles.length) {
2454
+ return createRBom(path, options);
2455
+ }
2456
+
2457
+ // Perl with Carton
2458
+ const cpanSnapshotFiles = getAllFiles(
2459
+ path,
2460
+ `${options.multiProject ? "**/" : ""}cpanfile.snapshot`,
2461
+ options,
2462
+ );
2463
+ if (cpanSnapshotFiles.length) {
2464
+ return createPerlBom(path, options);
2465
+ }
2466
+
2467
+ // Terraform and OpenTofu providers
2468
+ const tfLockFiles = getAllFiles(
2469
+ path,
2470
+ `${options.multiProject ? "**/" : ""}.terraform.lock.hcl`,
2471
+ options,
2472
+ );
2473
+ if (tfLockFiles.length) {
2474
+ return createTerraformBom(path, options);
2475
+ }
2288
2476
  }
2289
2477
 
2290
2478
  /**
@@ -2406,7 +2594,13 @@ async function createBomForPath(path, options) {
2406
2594
  } else if (
2407
2595
  (options.projectType &&
2408
2596
  !options.projectType?.includes("universal") &&
2409
- hasAnyProjectType(["oci"], options, false)) ||
2597
+ hasAnyProjectType(["oci"], options, false) &&
2598
+ // Explicit container types accept every documented image reference
2599
+ // style (postgres:15-alpine, shiftleft/scan-slim, registry:5000/ns/img),
2600
+ // but only for inputs that cannot be a local path: existing files and
2601
+ // directories keep flowing to the tar, oci-dir and source scanners.
2602
+ !safeExistsSync(path) &&
2603
+ isImageReference(path)) ||
2410
2604
  path.startsWith("docker.io") ||
2411
2605
  path.startsWith("quay.io") ||
2412
2606
  path.startsWith("ghcr.io") ||
@@ -2636,6 +2830,39 @@ async function createBomForPath(path, options) {
2636
2830
  if (PROJECT_TYPE_ALIASES["gleam"].includes(projectType[0])) {
2637
2831
  return await createGleamBom(path, options);
2638
2832
  }
2833
+ if (PROJECT_TYPE_ALIASES["julia"].includes(projectType[0])) {
2834
+ return await createJuliaBom(path, options);
2835
+ }
2836
+ if (PROJECT_TYPE_ALIASES["erlang"].includes(projectType[0])) {
2837
+ return await createErlangBom(path, options);
2838
+ }
2839
+ if (PROJECT_TYPE_ALIASES["ocaml"].includes(projectType[0])) {
2840
+ return await createOCamlBom(path, options);
2841
+ }
2842
+ if (PROJECT_TYPE_ALIASES["elm"].includes(projectType[0])) {
2843
+ return await createElmBom(path, options);
2844
+ }
2845
+ if (PROJECT_TYPE_ALIASES["crystal"].includes(projectType[0])) {
2846
+ return await createCrystalBom(path, options);
2847
+ }
2848
+ if (PROJECT_TYPE_ALIASES["nim"].includes(projectType[0])) {
2849
+ return await createNimBom(path, options);
2850
+ }
2851
+ if (PROJECT_TYPE_ALIASES["lua"].includes(projectType[0])) {
2852
+ return await createLuaBom(path, options);
2853
+ }
2854
+ if (PROJECT_TYPE_ALIASES["spack"].includes(projectType[0])) {
2855
+ return await createSpackBom(path, options);
2856
+ }
2857
+ if (PROJECT_TYPE_ALIASES["r"].includes(projectType[0])) {
2858
+ return createRBom(path, options);
2859
+ }
2860
+ if (PROJECT_TYPE_ALIASES["perl"].includes(projectType[0])) {
2861
+ return createPerlBom(path, options);
2862
+ }
2863
+ if (PROJECT_TYPE_ALIASES["terraform"].includes(projectType[0])) {
2864
+ return createTerraformBom(path, options);
2865
+ }
2639
2866
  if (PROJECT_TYPE_ALIASES["caxa"].includes(projectType[0])) {
2640
2867
  return await createCaxaBom(path, options);
2641
2868
  }
@@ -2645,6 +2872,9 @@ async function createBomForPath(path, options) {
2645
2872
  if (PROJECT_TYPE_ALIASES["vscode-extension"].includes(projectType[0])) {
2646
2873
  return await createVscodeExtensionBom(path, options);
2647
2874
  }
2875
+ if (PROJECT_TYPE_ALIASES["agentic"].includes(projectType[0])) {
2876
+ return await createAgenticBom(path, options);
2877
+ }
2648
2878
  if (PROJECT_TYPE_ALIASES["chrome-extension"].includes(projectType[0])) {
2649
2879
  return await createChromeExtensionBom(path, options);
2650
2880
  }