@cdxgen/cdxgen 13.6.0 → 13.7.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 (264) hide show
  1. package/README.md +15 -8
  2. package/bin/audit.js +7 -4
  3. package/bin/cdxgen.js +256 -37
  4. package/bin/convert.js +146 -22
  5. package/bin/evinse.js +25 -3
  6. package/bin/repl.js +47 -3
  7. package/bin/sign.js +211 -34
  8. package/bin/tracebom.js +18 -6
  9. package/bin/validate.js +18 -3
  10. package/bin/verify.js +113 -5
  11. package/data/behavior-taxonomy.schema.json +1491 -0
  12. package/data/cyclonedx-2.0-bundled.schema.json +18606 -5528
  13. package/data/cyclonedx-2.0-cryptography-defs.schema.json +857 -0
  14. package/data/pqc-migration.json +239 -0
  15. package/data/remediations.json +52 -0
  16. package/data/rules/cbom-security.yaml +4 -3
  17. package/data/rules/package-integrity.yaml +28 -0
  18. package/lib/audit/index.js +25 -3
  19. package/lib/cli/bomAssembly.js +80 -1
  20. package/lib/cli/cliOptions.js +121 -17
  21. package/lib/cli/index.js +609 -898
  22. package/lib/cli/jsBom.js +3 -0
  23. package/lib/cli/jvmBom.js +365 -40
  24. package/lib/cli/managedBom.js +19 -3
  25. package/lib/cli/nativeBom.js +10 -0
  26. package/lib/core/env.js +26 -0
  27. package/lib/core/fs.js +126 -3
  28. package/lib/core/globPatterns.js +218 -0
  29. package/lib/core/processTree.js +99 -12
  30. package/lib/core/projectConfig.js +332 -25
  31. package/lib/core/toolRegistry.js +15 -1
  32. package/lib/ecosystems/denoutils.js +2 -2
  33. package/lib/ecosystems/golem.js +3 -8
  34. package/lib/ecosystems/gradleutils.js +1082 -6
  35. package/lib/ecosystems/jsEvidence.js +90 -38
  36. package/lib/ecosystems/kosi.js +3 -5
  37. package/lib/ecosystems/npmVersionResolution.js +376 -0
  38. package/lib/ecosystems/parsers-python.js +89 -28
  39. package/lib/ecosystems/parsers-rust.js +117 -15
  40. package/lib/ecosystems/remote/huggingface.js +22 -0
  41. package/lib/ecosystems/rusi.js +2 -4
  42. package/lib/ecosystems/scalasem.js +2 -1
  43. package/lib/evinser/evinser.js +196 -34
  44. package/lib/evinser/scalasem.js +5 -1
  45. package/lib/helpers/agenticToolutils.js +112 -1
  46. package/lib/helpers/bomSigner.js +43 -9
  47. package/lib/helpers/jssSigner.js +1276 -0
  48. package/lib/inventory/agentBlueprint.js +193 -0
  49. package/lib/inventory/agentToolNames.js +145 -0
  50. package/lib/inventory/aiCollector.js +153 -7
  51. package/lib/inventory/aiInventory.js +44 -8
  52. package/lib/inventory/aiProviders.js +324 -0
  53. package/lib/inventory/bomUtils.js +8 -1
  54. package/lib/inventory/ciParsers/githubActionsLock.js +821 -0
  55. package/lib/inventory/citations.js +31 -2
  56. package/lib/inventory/communityAiConfigParser.js +978 -80
  57. package/lib/inventory/cyclonedx20.js +152 -0
  58. package/lib/inventory/cyclonedx20Common.js +286 -0
  59. package/lib/inventory/cyclonedx20Derived.js +159 -0
  60. package/lib/inventory/cyclonedx20Parties.js +552 -0
  61. package/lib/inventory/cyclonedx20Read.js +768 -0
  62. package/lib/inventory/cyclonedx20ReadCommon.js +374 -0
  63. package/lib/inventory/cyclonedx20ReadComponents.js +692 -0
  64. package/lib/inventory/cyclonedx20ReadContext.js +380 -0
  65. package/lib/inventory/cyclonedx20ReadEvidence.js +466 -0
  66. package/lib/inventory/cyclonedx20ReadSections.js +599 -0
  67. package/lib/inventory/cyclonedx20Render.js +766 -0
  68. package/lib/inventory/cyclonedx20RenderComponents.js +716 -0
  69. package/lib/inventory/cyclonedx20RenderDefinitions.js +405 -0
  70. package/lib/inventory/cyclonedx20RenderEvidence.js +726 -0
  71. package/lib/inventory/cyclonedx20RenderHardware.js +203 -0
  72. package/lib/inventory/cyclonedx20RenderPatents.js +174 -0
  73. package/lib/inventory/cyclonedx20RenderRefIds.js +314 -0
  74. package/lib/inventory/cyclonedx20RenderSections.js +499 -0
  75. package/lib/inventory/cyclonedx20Tables.js +594 -0
  76. package/lib/inventory/deps.js +106 -13
  77. package/lib/inventory/dosai.js +236 -1
  78. package/lib/inventory/dosaiParsers.js +3 -6
  79. package/lib/inventory/dotnetRuntime.js +164 -14
  80. package/lib/inventory/ecosystemFormulationParsers.js +979 -0
  81. package/lib/inventory/envcontext.js +132 -38
  82. package/lib/inventory/evidenceUtils.js +2 -1
  83. package/lib/inventory/formulationParsers.js +95 -13
  84. package/lib/inventory/hbom.js +45 -6
  85. package/lib/inventory/hbomLoader.js +166 -0
  86. package/lib/inventory/mcpConfigParser.js +5 -0
  87. package/lib/inventory/occurrenceKey.js +90 -0
  88. package/lib/inventory/pqcMigration.js +426 -0
  89. package/lib/inventory/rustFormulationParser.js +21 -10
  90. package/lib/inventory/source.js +65 -6
  91. package/lib/parsers/huggingfaceManifest.js +9 -1
  92. package/lib/parsers/huggingfaceUtils.js +18 -0
  93. package/lib/parsers/kiroPermissions.js +166 -0
  94. package/lib/server/server.js +36 -34
  95. package/lib/stages/postgen/postgen.js +41 -1
  96. package/lib/stages/postgen/specVersionCompat.js +76 -0
  97. package/lib/validator/bomValidator.js +8 -1
  98. package/lib/validator/complianceEngine.js +30 -3
  99. package/lib/validator/complianceRules.js +1416 -4
  100. package/lib/validator/generated/validate-2.0.mjs +57554 -13851
  101. package/lib/validator/index.js +48 -7
  102. package/lib/validator/reporters/json.js +6 -0
  103. package/package.json +9 -9
  104. package/types/bin/repl.d.ts.map +1 -1
  105. package/types/lib/audit/index.d.ts +6 -2
  106. package/types/lib/audit/index.d.ts.map +1 -1
  107. package/types/lib/cli/bomAssembly.d.ts +16 -0
  108. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  109. package/types/lib/cli/cliOptions.d.ts +6 -0
  110. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  111. package/types/lib/cli/index.d.ts.map +1 -1
  112. package/types/lib/cli/jsBom.d.ts +2 -1
  113. package/types/lib/cli/jsBom.d.ts.map +1 -1
  114. package/types/lib/cli/jvmBom.d.ts +15 -0
  115. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  116. package/types/lib/cli/managedBom.d.ts.map +1 -1
  117. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  118. package/types/lib/core/boundedFile.d.ts +30 -0
  119. package/types/lib/core/boundedFile.d.ts.map +1 -1
  120. package/types/lib/core/env.d.ts +10 -0
  121. package/types/lib/core/env.d.ts.map +1 -1
  122. package/types/lib/core/fs.d.ts +4 -0
  123. package/types/lib/core/fs.d.ts.map +1 -1
  124. package/types/lib/core/globPatterns.d.ts +70 -0
  125. package/types/lib/core/globPatterns.d.ts.map +1 -0
  126. package/types/lib/core/paths.d.ts +9 -0
  127. package/types/lib/core/paths.d.ts.map +1 -1
  128. package/types/lib/core/processTree.d.ts +16 -5
  129. package/types/lib/core/processTree.d.ts.map +1 -1
  130. package/types/lib/core/projectConfig.d.ts +47 -8
  131. package/types/lib/core/projectConfig.d.ts.map +1 -1
  132. package/types/lib/core/toolRegistry.d.ts.map +1 -1
  133. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  134. package/types/lib/ecosystems/gradleutils.d.ts +248 -8
  135. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  136. package/types/lib/ecosystems/jsEvidence.d.ts +14 -1
  137. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  138. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  139. package/types/lib/ecosystems/npmVersionResolution.d.ts +119 -0
  140. package/types/lib/ecosystems/npmVersionResolution.d.ts.map +1 -0
  141. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  142. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  143. package/types/lib/ecosystems/pythonutils.d.ts +1 -1
  144. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  145. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  146. package/types/lib/ecosystems/scalasem.d.ts +58 -16
  147. package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
  148. package/types/lib/evinser/evinser.d.ts +61 -9
  149. package/types/lib/evinser/evinser.d.ts.map +1 -1
  150. package/types/lib/evinser/scalasem.d.ts.map +1 -1
  151. package/types/lib/helpers/agenticToolutils.d.ts +53 -19
  152. package/types/lib/helpers/agenticToolutils.d.ts.map +1 -1
  153. package/types/lib/helpers/bomSigner.d.ts +20 -3
  154. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  155. package/types/lib/helpers/jssSigner.d.ts +288 -0
  156. package/types/lib/helpers/jssSigner.d.ts.map +1 -0
  157. package/types/lib/helpers/vsixutils.d.ts +303 -19
  158. package/types/lib/helpers/vsixutils.d.ts.map +1 -1
  159. package/types/lib/inventory/agentBlueprint.d.ts +70 -0
  160. package/types/lib/inventory/agentBlueprint.d.ts.map +1 -0
  161. package/types/lib/inventory/agentToolNames.d.ts +51 -0
  162. package/types/lib/inventory/agentToolNames.d.ts.map +1 -0
  163. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  164. package/types/lib/inventory/aiInventory.d.ts.map +1 -1
  165. package/types/lib/inventory/aiProviders.d.ts +85 -0
  166. package/types/lib/inventory/aiProviders.d.ts.map +1 -0
  167. package/types/lib/inventory/bomUtils.d.ts.map +1 -1
  168. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts +101 -0
  169. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts.map +1 -0
  170. package/types/lib/inventory/citations.d.ts +5 -0
  171. package/types/lib/inventory/citations.d.ts.map +1 -1
  172. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  173. package/types/lib/inventory/cyclonedx20.d.ts +99 -0
  174. package/types/lib/inventory/cyclonedx20.d.ts.map +1 -0
  175. package/types/lib/inventory/cyclonedx20Common.d.ts +102 -0
  176. package/types/lib/inventory/cyclonedx20Common.d.ts.map +1 -0
  177. package/types/lib/inventory/cyclonedx20Derived.d.ts +74 -0
  178. package/types/lib/inventory/cyclonedx20Derived.d.ts.map +1 -0
  179. package/types/lib/inventory/cyclonedx20Parties.d.ts +91 -0
  180. package/types/lib/inventory/cyclonedx20Parties.d.ts.map +1 -0
  181. package/types/lib/inventory/cyclonedx20Read.d.ts +51 -0
  182. package/types/lib/inventory/cyclonedx20Read.d.ts.map +1 -0
  183. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts +69 -0
  184. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts.map +1 -0
  185. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts +77 -0
  186. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts.map +1 -0
  187. package/types/lib/inventory/cyclonedx20ReadContext.d.ts +118 -0
  188. package/types/lib/inventory/cyclonedx20ReadContext.d.ts.map +1 -0
  189. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts +40 -0
  190. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts.map +1 -0
  191. package/types/lib/inventory/cyclonedx20ReadSections.d.ts +45 -0
  192. package/types/lib/inventory/cyclonedx20ReadSections.d.ts.map +1 -0
  193. package/types/lib/inventory/cyclonedx20Render.d.ts +53 -0
  194. package/types/lib/inventory/cyclonedx20Render.d.ts.map +1 -0
  195. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts +73 -0
  196. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts.map +1 -0
  197. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts +29 -0
  198. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts.map +1 -0
  199. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts +110 -0
  200. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts.map +1 -0
  201. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts +42 -0
  202. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts.map +1 -0
  203. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts +26 -0
  204. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts.map +1 -0
  205. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts +55 -0
  206. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts.map +1 -0
  207. package/types/lib/inventory/cyclonedx20RenderSections.d.ts +45 -0
  208. package/types/lib/inventory/cyclonedx20RenderSections.d.ts.map +1 -0
  209. package/types/lib/inventory/cyclonedx20Tables.d.ts +134 -0
  210. package/types/lib/inventory/cyclonedx20Tables.d.ts.map +1 -0
  211. package/types/lib/inventory/deps.d.ts +35 -2
  212. package/types/lib/inventory/deps.d.ts.map +1 -1
  213. package/types/lib/inventory/dosai.d.ts +19 -0
  214. package/types/lib/inventory/dosai.d.ts.map +1 -1
  215. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  216. package/types/lib/inventory/dotnetRuntime.d.ts +51 -4
  217. package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -1
  218. package/types/lib/inventory/ecosystemFormulationParsers.d.ts +73 -0
  219. package/types/lib/inventory/ecosystemFormulationParsers.d.ts.map +1 -0
  220. package/types/lib/inventory/envcontext.d.ts +22 -6
  221. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  222. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  223. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  224. package/types/lib/inventory/hbom.d.ts +11 -0
  225. package/types/lib/inventory/hbom.d.ts.map +1 -1
  226. package/types/lib/inventory/hbomLoader.d.ts +54 -0
  227. package/types/lib/inventory/hbomLoader.d.ts.map +1 -1
  228. package/types/lib/inventory/jvmLocalRepos.d.ts +5 -1
  229. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -1
  230. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  231. package/types/lib/inventory/occurrenceKey.d.ts +52 -0
  232. package/types/lib/inventory/occurrenceKey.d.ts.map +1 -0
  233. package/types/lib/inventory/pqcMigration.d.ts +84 -0
  234. package/types/lib/inventory/pqcMigration.d.ts.map +1 -0
  235. package/types/lib/inventory/rustFormulationParser.d.ts +7 -2
  236. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  237. package/types/lib/inventory/scalaCoords.d.ts.map +1 -1
  238. package/types/lib/inventory/scalaDedupe.d.ts +43 -0
  239. package/types/lib/inventory/scalaDedupe.d.ts.map +1 -0
  240. package/types/lib/inventory/source.d.ts +15 -0
  241. package/types/lib/inventory/source.d.ts.map +1 -1
  242. package/types/lib/parsers/huggingfaceManifest.d.ts +10 -1
  243. package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -1
  244. package/types/lib/parsers/huggingfaceUtils.d.ts +12 -0
  245. package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
  246. package/types/lib/parsers/kiroPermissions.d.ts +62 -0
  247. package/types/lib/parsers/kiroPermissions.d.ts.map +1 -0
  248. package/types/lib/parsers/vscodeExtensionId.d.ts +48 -0
  249. package/types/lib/parsers/vscodeExtensionId.d.ts.map +1 -0
  250. package/types/lib/server/server.d.ts.map +1 -1
  251. package/types/lib/stages/postgen/postgen.d.ts +7 -0
  252. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  253. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  254. package/types/lib/stages/postgen/specVersionCompat.d.ts +25 -0
  255. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  256. package/types/lib/validator/bomValidator.d.ts +5 -1
  257. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  258. package/types/lib/validator/complianceEngine.d.ts +4 -4
  259. package/types/lib/validator/complianceEngine.d.ts.map +1 -1
  260. package/types/lib/validator/complianceRules.d.ts +14 -2
  261. package/types/lib/validator/complianceRules.d.ts.map +1 -1
  262. package/types/lib/validator/index.d.ts +10 -0
  263. package/types/lib/validator/index.d.ts.map +1 -1
  264. package/types/lib/validator/reporters/json.d.ts.map +1 -1
@@ -94,20 +94,35 @@ const POST_BUILD_SUPPORTED_PROJECT_TYPES = new Set([
94
94
  // ---------------------------------------------------------------------------
95
95
 
96
96
  /**
97
- * The formulation privacy notice, shared by every path that turns formulation
98
- * collection on automatically: the warning about emails and secrets is
99
- * identical whichever caller adds the section.
97
+ * The notice for formulation that cdxgen turned on by itself. It names what
98
+ * turned formulation on, and, when the BOM is submitted to a server, the
99
+ * warning also names that server, as it does for an explicit
100
+ * --include-formulation.
100
101
  *
102
+ * @param {object} options The options object
103
+ * @param {string} reasons What turned formulation on, such as "CI=true"
101
104
  * @returns {OptionsWarning} The notice.
102
105
  */
103
- function formulationPrivacyNotice() {
106
+ function autoFormulationNotice(options, reasons) {
107
+ if (options.serverUrl) {
108
+ return {
109
+ level: "warn",
110
+ message: `WARNING: Automatically collecting formulation information for ${reasons}. The formulation section may include sensitive data such as emails and secrets. This data will be submitted to '${options.serverUrl}' automatically. Pass --no-include-formulation to leave it out.`,
111
+ };
112
+ }
104
113
  return {
105
114
  level: "info",
106
- message:
107
- "NOTE: Automatically collecting formulation information. The section may include sensitive data such as emails and secrets.\nPlease review the generated SBOM before distribution or LLM training.",
115
+ message: `NOTE: Automatically collecting formulation information for ${reasons}. The section may include sensitive data such as emails and secrets. Pass --no-include-formulation to leave it out.\nPlease review the generated SBOM before distribution or LLM training.`,
108
116
  };
109
117
  }
110
118
 
119
+ /**
120
+ * Options objects whose formulation notes were already reported, so the CLI,
121
+ * which applies the advanced options twice, prints each note once.
122
+ */
123
+ const formulationRefusalNoted = new WeakSet();
124
+ const secureFormulationNoteNoted = new WeakSet();
125
+
111
126
  /**
112
127
  * Check whether a value was explicitly provided by the user (i.e., is not
113
128
  * the yargs default). Yargs always populates default values, so we cannot
@@ -400,6 +415,28 @@ function resolveIntrospectOption(args, argv) {
400
415
  : undefined;
401
416
  }
402
417
 
418
+ /**
419
+ * Whether the operator explicitly refused formulation with
420
+ * `--no-include-formulation`, `--include-formulation=false` or
421
+ * `CDXGEN_INCLUDE_FORMULATION=false`.
422
+ *
423
+ * @param {string[]} argv Raw command-line arguments the parser was given.
424
+ * @returns {boolean} True when formulation was refused explicitly.
425
+ */
426
+ function isFormulationRefused(argv) {
427
+ return (
428
+ operatorOptionChoice("include-formulation", {
429
+ argv,
430
+ boolean: true,
431
+ env: {
432
+ CDXGEN_INCLUDE_FORMULATION: readEnvironmentVariable(
433
+ "CDXGEN_INCLUDE_FORMULATION",
434
+ ),
435
+ },
436
+ }) === false
437
+ );
438
+ }
439
+
403
440
  export function buildInitialOptions(
404
441
  args,
405
442
  { filePath, isRemoteOrPurl, argv = process.argv, projectConfig },
@@ -427,6 +464,11 @@ export function buildInitialOptions(
427
464
  // explicit --no-introspect stays `false` and beats both, while an
428
465
  // unmentioned flag stays undefined so a profile can still enable it.
429
466
  introspect: resolveIntrospectOption(args, argv),
467
+ // An explicit --no-include-formulation (or CDXGEN_INCLUDE_FORMULATION
468
+ // set to false) is the operator's refusal, which no automatic trigger
469
+ // such as CI=true, a profile, obom or cbom may override. The yargs
470
+ // default is also false, so only the raw arguments tell them apart.
471
+ includeFormulationRefused: isFormulationRefused(argv) || undefined,
430
472
  // License normalization and enrichment are on by default; the only escape
431
473
  // hatch is the corresponding environment variable.
432
474
  licenseEnhance:
@@ -439,6 +481,10 @@ export function buildInitialOptions(
439
481
  readEnvironmentVariable("CDXGEN_LICENSE_REF") === "true",
440
482
  });
441
483
 
484
+ // A command default such as aibom's does not outrank the refusal either.
485
+ if (res.includeFormulationRefused) {
486
+ res.includeFormulation = false;
487
+ }
442
488
  if (res.licenseEnhance !== undefined) {
443
489
  process.env.CDXGEN_LICENSE_ENHANCE = String(res.licenseEnhance);
444
490
  }
@@ -628,6 +674,8 @@ export function applyPostConstructionOverrides(options, context) {
628
674
  * @param {object} options The options object
629
675
  * @param {object} [context]
630
676
  * @param {boolean} [context.isSecureMode] Whether cdxgen runs in secure mode
677
+ * @param {string} [context.invokedCommandName] Binary name (e.g. "cbom"),
678
+ * which can turn on formulation
631
679
  * @returns {OptionsWarning[]} Warnings for the caller
632
680
  */
633
681
  export function applyAdvancedOptions(options, context = {}) {
@@ -635,6 +683,7 @@ export function applyAdvancedOptions(options, context = {}) {
635
683
  const warnings = [];
636
684
  const isHbomOnly = isHbomOnlyProjectTypes(options.projectType);
637
685
  const includeFormulationBeforeProfiles = options.includeFormulation === true;
686
+ const formulationRefused = options.includeFormulationRefused === true;
638
687
  const introspectExplicitlyDisabled = options.introspect === false;
639
688
 
640
689
  // --- Profile expansion -------------------------------------------------
@@ -672,7 +721,7 @@ export function applyAdvancedOptions(options, context = {}) {
672
721
  options.introspectAnnotate = options.introspectAnnotate !== false;
673
722
  // The ledger's own record of what ran; formulation is where a consumer
674
723
  // looks for the build environment the SBOM was produced in.
675
- options.includeFormulation = !isHbomOnly;
724
+ options.includeFormulation = !isHbomOnly && !formulationRefused;
676
725
  options.evidence = true;
677
726
  break;
678
727
  case "ml-tiny":
@@ -752,17 +801,67 @@ export function applyAdvancedOptions(options, context = {}) {
752
801
  });
753
802
  }
754
803
 
755
- // --- BOM audit → auto-formulation --------------------------------------
756
- const introspectProfileAddsFormulation =
757
- options.profile === "introspect" && !includeFormulationBeforeProfiles;
758
- if (options.bomAudit || introspectProfileAddsFormulation) {
759
- if (isHbomOnly) {
760
- // HBOM-only: skip formulation
804
+ // --- Auto-formulation: BOM audit, profiles, CI, obom and cbom ----------
805
+ // Formulation is included without a flag when a BOM audit reads it, when
806
+ // the research or introspect profile runs, in CI (CI=true), and for obom
807
+ // (an OS project type such as os, linux or windows) and cbom output
808
+ // (cdxgen#859). These runs are where the build environment and inputs are
809
+ // wanted next to the inventory. Formulation does not supply the CISA 2026
810
+ // generation context element: CISA-MIN-004 reads metadata.lifecycles.
811
+ // An explicit --no-include-formulation wins over every trigger.
812
+ const profileAddsFormulation =
813
+ ["research", "introspect"].includes(options.profile) &&
814
+ !includeFormulationBeforeProfiles;
815
+ const autoFormulationReasons = [];
816
+ if (options.bomAudit) {
817
+ autoFormulationReasons.push("a BOM audit");
818
+ }
819
+ if (profileAddsFormulation) {
820
+ autoFormulationReasons.push(`the ${options.profile} profile`);
821
+ }
822
+ if ((readEnvironmentVariable("CI") || "").toLowerCase() === "true") {
823
+ autoFormulationReasons.push("CI=true");
824
+ }
825
+ if (hasOsProjectType(options.projectType)) {
826
+ autoFormulationReasons.push("an OS project type");
827
+ }
828
+ if (`${context.invokedCommandName || ""}`.includes("cbom")) {
829
+ autoFormulationReasons.push("the cbom command");
830
+ }
831
+ if (autoFormulationReasons.length && !isHbomOnly) {
832
+ const reasons = autoFormulationReasons.join(", ");
833
+ if (formulationRefused) {
834
+ options.includeFormulation = false;
835
+ if (!formulationRefusalNoted.has(options)) {
836
+ formulationRefusalNoted.add(options);
837
+ warnings.push({
838
+ level: "info",
839
+ message: `NOTE: Formulation stays off because it was refused explicitly (--no-include-formulation, --include-formulation=false or CDXGEN_INCLUDE_FORMULATION=false), although ${reasons} would include it.`,
840
+ });
841
+ }
761
842
  } else if (!options.includeFormulation) {
762
- warnings.push(formulationPrivacyNotice());
763
- options.includeFormulation = true;
764
- } else if (introspectProfileAddsFormulation) {
765
- warnings.push(formulationPrivacyNotice());
843
+ if (options.serverUrl && secureMode) {
844
+ // Secure mode refuses to submit formulation to a server, so an
845
+ // automatic default must not turn a secure run into a failed one.
846
+ if (!secureFormulationNoteNoted.has(options)) {
847
+ secureFormulationNoteNoted.add(options);
848
+ warnings.push({
849
+ level: "info",
850
+ message: `NOTE: Formulation is not collected automatically for ${reasons} because secure mode does not submit formulation to '${options.serverUrl}'. Pass --include-formulation to request it.`,
851
+ });
852
+ }
853
+ } else {
854
+ warnings.push(autoFormulationNotice(options, reasons));
855
+ options.includeFormulation = true;
856
+ }
857
+ } else if (profileAddsFormulation) {
858
+ warnings.push(autoFormulationNotice(options, reasons));
859
+ }
860
+ // Formulation that no flag asked for leaves out the scanning host's
861
+ // certificates, authorized keys and keychain items (see
862
+ // addFormulationSection).
863
+ if (options.includeFormulation && !includeFormulationBeforeProfiles) {
864
+ options.formulationAutomatic = true;
766
865
  }
767
866
  }
768
867
 
@@ -795,6 +894,8 @@ export function applyAdvancedOptions(options, context = {}) {
795
894
  * @param {object} [context.projectConfig] Sanitized config file contents,
796
895
  * whose metadata properties merge
797
896
  * with the other sources'
897
+ * @param {string[]} [context.argv] Raw command-line arguments,
898
+ * process.argv when absent
798
899
  * @returns {{ options: object, warnings: OptionsWarning[] }}
799
900
  */
800
901
  export function buildOptionsFromArgs(args, context) {
@@ -805,6 +906,7 @@ export function buildOptionsFromArgs(args, context) {
805
906
  userSetSpecVersion,
806
907
  isDryRun = false,
807
908
  projectConfig,
909
+ argv,
808
910
  } = context;
809
911
 
810
912
  const expandedArgs = applyCommandNameDefaults(args, invokedCommandName);
@@ -812,6 +914,7 @@ export function buildOptionsFromArgs(args, context) {
812
914
  filePath,
813
915
  isRemoteOrPurl,
814
916
  projectConfig,
917
+ ...(argv ? { argv } : {}),
815
918
  });
816
919
  const phase3Warnings = applyPostConstructionOverrides(options, {
817
920
  invokedCommandName,
@@ -820,6 +923,7 @@ export function buildOptionsFromArgs(args, context) {
820
923
  });
821
924
  const phase4Warnings = applyAdvancedOptions(options, {
822
925
  isSecureMode: context.isSecureMode,
926
+ invokedCommandName,
823
927
  });
824
928
 
825
929
  return {