@cdxgen/cdxgen 13.0.1 → 13.1.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 (155) hide show
  1. package/README.md +26 -13
  2. package/bin/audit.js +6 -0
  3. package/bin/cdxgen.js +125 -4
  4. package/bin/evinse.js +1 -1
  5. package/data/component-tags.json +8 -1
  6. package/data/frameworks-list.json +86 -1
  7. package/data/remediations.json +1144 -0
  8. package/data/rules/asar-archives.yaml +1 -1
  9. package/data/rules/build-fidelity.yaml +782 -0
  10. package/data/rules/package-integrity.yaml +13 -13
  11. package/lib/audit/index.js +48 -4
  12. package/lib/audit/scoring.js +2 -8
  13. package/lib/cli/bomAssembly.js +20 -1
  14. package/lib/cli/cliOptions.js +94 -7
  15. package/lib/cli/index.js +76 -48
  16. package/lib/cli/jsBom.js +32 -3
  17. package/lib/cli/jvmBom.js +1494 -1315
  18. package/lib/cli/managedBom.js +97 -28
  19. package/lib/cli/nativeBom.js +189 -10
  20. package/lib/core/buildLedger.js +799 -0
  21. package/lib/core/deferredExit.js +141 -0
  22. package/lib/core/env.js +69 -1
  23. package/lib/core/fs.js +60 -0
  24. package/lib/core/logger.js +12 -99
  25. package/lib/core/severity.js +16 -0
  26. package/lib/core/syncFileWriter.js +106 -0
  27. package/lib/ecosystems/ecosystems.js +9 -0
  28. package/lib/ecosystems/gradleutils.js +355 -15
  29. package/lib/ecosystems/parsers-js.js +26 -0
  30. package/lib/ecosystems/parsers-jvm.js +9 -0
  31. package/lib/ecosystems/parsers-misc.js +16 -2
  32. package/lib/ecosystems/parsers-python.js +171 -35
  33. package/lib/ecosystems/parsers-rust.js +12 -2
  34. package/lib/ecosystems/pypiClassifiers.js +326 -0
  35. package/lib/ecosystems/pythonutils.js +49 -1
  36. package/lib/ecosystems/rubyutils.js +13 -0
  37. package/lib/evinser/evinser.js +30 -12
  38. package/lib/helpers/remote/dependency-track.js +81 -14
  39. package/lib/inventory/auditCategories.js +9 -0
  40. package/lib/inventory/depsUtils.js +72 -0
  41. package/lib/inventory/dosai.js +431 -22
  42. package/lib/inventory/envcontext.js +206 -18
  43. package/lib/inventory/fetchBatch.js +57 -0
  44. package/lib/inventory/jvmToolEnv.js +593 -0
  45. package/lib/inventory/osinfo.js +1 -0
  46. package/lib/inventory/toolRequirements.js +903 -0
  47. package/lib/managers/binary.js +24 -0
  48. package/lib/managers/docker.js +26 -5
  49. package/lib/server/server.js +1 -1
  50. package/lib/stages/postgen/annotationBuilder.js +97 -0
  51. package/lib/stages/postgen/auditBom.js +76 -79
  52. package/lib/stages/postgen/introspection/annotate.js +320 -0
  53. package/lib/stages/postgen/introspection/commandFacts.js +293 -0
  54. package/lib/stages/postgen/introspection/emit.js +192 -0
  55. package/lib/stages/postgen/introspection/formulationEvidence.js +427 -0
  56. package/lib/stages/postgen/introspection/markers.js +227 -0
  57. package/lib/stages/postgen/introspection/reflect.js +1214 -0
  58. package/lib/stages/postgen/introspection/report.js +1208 -0
  59. package/lib/stages/postgen/introspection/score.js +1067 -0
  60. package/lib/stages/postgen/introspection/shapeCommand.js +304 -0
  61. package/lib/stages/postgen/parentEdge.js +156 -0
  62. package/lib/stages/postgen/postgen.js +115 -2
  63. package/lib/stages/postgen/ruleEngine.js +17 -0
  64. package/lib/stages/pregen/envAudit.js +42 -2
  65. package/lib/stages/pregen/pregen.js +1171 -6
  66. package/lib/validator/bomValidator.js +11 -2
  67. package/package.json +14 -14
  68. package/types/lib/audit/index.d.ts.map +1 -1
  69. package/types/lib/audit/scoring.d.ts +2 -8
  70. package/types/lib/audit/scoring.d.ts.map +1 -1
  71. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  72. package/types/lib/cli/cliOptions.d.ts +2 -1
  73. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  74. package/types/lib/cli/index.d.ts +8 -0
  75. package/types/lib/cli/index.d.ts.map +1 -1
  76. package/types/lib/cli/jsBom.d.ts.map +1 -1
  77. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  78. package/types/lib/cli/managedBom.d.ts.map +1 -1
  79. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  80. package/types/lib/core/buildLedger.d.ts +272 -0
  81. package/types/lib/core/buildLedger.d.ts.map +1 -0
  82. package/types/lib/core/deferredExit.d.ts +84 -0
  83. package/types/lib/core/deferredExit.d.ts.map +1 -0
  84. package/types/lib/core/env.d.ts +22 -1
  85. package/types/lib/core/env.d.ts.map +1 -1
  86. package/types/lib/core/fs.d.ts +21 -0
  87. package/types/lib/core/fs.d.ts.map +1 -1
  88. package/types/lib/core/logger.d.ts +2 -11
  89. package/types/lib/core/logger.d.ts.map +1 -1
  90. package/types/lib/core/severity.d.ts +11 -0
  91. package/types/lib/core/severity.d.ts.map +1 -0
  92. package/types/lib/core/syncFileWriter.d.ts +33 -0
  93. package/types/lib/core/syncFileWriter.d.ts.map +1 -0
  94. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  95. package/types/lib/ecosystems/gradleutils.d.ts +33 -0
  96. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  97. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  98. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  99. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  100. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  101. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  102. package/types/lib/ecosystems/pypiClassifiers.d.ts +80 -0
  103. package/types/lib/ecosystems/pypiClassifiers.d.ts.map +1 -0
  104. package/types/lib/ecosystems/pythonutils.d.ts +20 -0
  105. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  106. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  107. package/types/lib/evinser/evinser.d.ts +5 -1
  108. package/types/lib/evinser/evinser.d.ts.map +1 -1
  109. package/types/lib/helpers/remote/dependency-track.d.ts +45 -4
  110. package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
  111. package/types/lib/inventory/auditCategories.d.ts +8 -0
  112. package/types/lib/inventory/auditCategories.d.ts.map +1 -1
  113. package/types/lib/inventory/depsUtils.d.ts.map +1 -1
  114. package/types/lib/inventory/dosai.d.ts +20 -0
  115. package/types/lib/inventory/dosai.d.ts.map +1 -1
  116. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  117. package/types/lib/inventory/fetchBatch.d.ts +9 -0
  118. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  119. package/types/lib/inventory/jvmToolEnv.d.ts +189 -0
  120. package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -0
  121. package/types/lib/inventory/osinfo.d.ts.map +1 -1
  122. package/types/lib/inventory/toolRequirements.d.ts +216 -0
  123. package/types/lib/inventory/toolRequirements.d.ts.map +1 -0
  124. package/types/lib/managers/binary.d.ts.map +1 -1
  125. package/types/lib/managers/docker.d.ts.map +1 -1
  126. package/types/lib/stages/postgen/annotationBuilder.d.ts +53 -0
  127. package/types/lib/stages/postgen/annotationBuilder.d.ts.map +1 -0
  128. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
  129. package/types/lib/stages/postgen/introspection/annotate.d.ts +81 -0
  130. package/types/lib/stages/postgen/introspection/annotate.d.ts.map +1 -0
  131. package/types/lib/stages/postgen/introspection/commandFacts.d.ts +32 -0
  132. package/types/lib/stages/postgen/introspection/commandFacts.d.ts.map +1 -0
  133. package/types/lib/stages/postgen/introspection/emit.d.ts +71 -0
  134. package/types/lib/stages/postgen/introspection/emit.d.ts.map +1 -0
  135. package/types/lib/stages/postgen/introspection/formulationEvidence.d.ts +154 -0
  136. package/types/lib/stages/postgen/introspection/formulationEvidence.d.ts.map +1 -0
  137. package/types/lib/stages/postgen/introspection/markers.d.ts +57 -0
  138. package/types/lib/stages/postgen/introspection/markers.d.ts.map +1 -0
  139. package/types/lib/stages/postgen/introspection/reflect.d.ts +77 -0
  140. package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -0
  141. package/types/lib/stages/postgen/introspection/report.d.ts +85 -0
  142. package/types/lib/stages/postgen/introspection/report.d.ts.map +1 -0
  143. package/types/lib/stages/postgen/introspection/score.d.ts +149 -0
  144. package/types/lib/stages/postgen/introspection/score.d.ts.map +1 -0
  145. package/types/lib/stages/postgen/introspection/shapeCommand.d.ts +79 -0
  146. package/types/lib/stages/postgen/introspection/shapeCommand.d.ts.map +1 -0
  147. package/types/lib/stages/postgen/parentEdge.d.ts +35 -0
  148. package/types/lib/stages/postgen/parentEdge.d.ts.map +1 -0
  149. package/types/lib/stages/postgen/postgen.d.ts +2 -2
  150. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  151. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  152. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  153. package/types/lib/stages/pregen/pregen.d.ts +131 -0
  154. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  155. package/types/lib/validator/bomValidator.d.ts.map +1 -1
package/README.md CHANGED
@@ -32,15 +32,16 @@ Supported output document formats:
32
32
 
33
33
  ## Choose your path
34
34
 
35
- | Persona | What cdxgen helps you do | First command | Read next |
36
- | --------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
37
- | **Developers** | Generate a CycloneDX BOM from a local repo, git URL, purl, or container image | `cdxgen -o bom.json .` | [CLI Usage][docs-cli], [Supported Project Types][docs-project-types] |
38
- | **AI platform teams** | Generate AI/ML BOMs, catalog prompt/model/MCP surfaces, and run AI-BOM governance | `aibom .` | [AI-BOM Guide](docs/AI_BOM.md), [AI-BOM lesson](docs/LESSON15.md) |
39
- | **Hardware teams** | Generate an HBOM or merged HBOM+OBOM host view for the current host | `hbom -o hbom.json` | [HBOM guide](docs/HBOM.md), [HBOM lesson](docs/LESSON13.md) |
40
- | **AppSec** | Enrich BOMs with evidence, run BOM audit rules, and feed downstream security workflows | `cdxgen -o bom.json --profile appsec --evidence --bom-audit .` | [BOM Audit](docs/BOM_AUDIT.md), [Threat Model](docs/THREAT_MODEL.md) |
41
- | **SOC analysts** | Build OBOM inventories for live hosts and triage runtime posture issues | `obom -o obom.json --deep --bom-audit --bom-audit-categories obom-runtime` | [OBOM lessons](docs/OBOM_LESSONS.md), [Server Usage][docs-server] |
42
- | **Compliance teams** | Validate BOM quality, check SCVS/CRA posture, and export SPDX deliverables | `cdx-validate -i bom.json --benchmark scvs-l2,cra` | [cdx-validate](docs/CDX_VALIDATE.md), [cdx-convert](docs/CDX_CONVERT.md), [Permissions][docs-permissions] |
43
- | **Security Teams** | Dynamically trace executions to capture cryptographic activities, CBOM properties, software components, and services | `tracebom --cbom-output cbom.json -- npm test` | [Threat Model](docs/THREAT_MODEL.md) |
35
+ | Persona | What cdxgen helps you do | First command | Read next |
36
+ | --------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
37
+ | **Developers** | Generate a CycloneDX BOM from a local repo, git URL, purl, or container image | `cdxgen -o bom.json .` | [CLI Usage][docs-cli], [Supported Project Types][docs-project-types] |
38
+ | **AI platform teams** | Generate AI/ML BOMs, catalog prompt/model/MCP surfaces, and run AI-BOM governance | `aibom .` | [AI-BOM Guide](docs/AI_BOM.md), [AI-BOM lesson](docs/LESSON15.md) |
39
+ | **Hardware teams** | Generate an HBOM or merged HBOM+OBOM host view for the current host | `hbom -o hbom.json` | [HBOM guide](docs/HBOM.md), [HBOM lesson](docs/LESSON13.md) |
40
+ | **AppSec** | Enrich BOMs with evidence, run BOM audit rules, and feed downstream security workflows | `cdxgen -o bom.json --profile appsec --evidence --bom-audit .` | [BOM Audit](docs/BOM_AUDIT.md), [Threat Model](docs/THREAT_MODEL.md) |
41
+ | **Build engineers** | Grade how completely the SBOM captured the project, and get ranked fixes when the build environment degraded it | `cdxgen --profile introspect --introspect-fail-below 70 -o bom.json .` | [Build Introspection](docs/INTROSPECTION.md), [Fidelity loop skill](.agents/skills/sbom-fidelity-loop/SKILL.md) |
42
+ | **SOC analysts** | Build OBOM inventories for live hosts and triage runtime posture issues | `obom -o obom.json --deep --bom-audit --bom-audit-categories obom-runtime` | [OBOM lessons](docs/OBOM_LESSONS.md), [Server Usage][docs-server] |
43
+ | **Compliance teams** | Validate BOM quality, check SCVS/CRA posture, and export SPDX deliverables | `cdx-validate -i bom.json --benchmark scvs-l2,cra` | [cdx-validate](docs/CDX_VALIDATE.md), [cdx-convert](docs/CDX_CONVERT.md), [Permissions][docs-permissions] |
44
+ | **Security Teams** | Dynamically trace executions to capture cryptographic activities, CBOM properties, software components, and services | `tracebom --cbom-output cbom.json -- npm test` | [Threat Model](docs/THREAT_MODEL.md) |
44
45
 
45
46
  ### Role-based quick starts
46
47
 
@@ -120,6 +121,7 @@ Sections include:
120
121
  - [MCP Inventory](docs/MCP.md)
121
122
  - [REPL Guide](docs/REPL.md)
122
123
  - [Custom Properties](docs/CUSTOM_PROPERTIES.md)
124
+ - [Claude Code Plugin](claude-plugin/README.md)
123
125
  - [Deprecations](docs/DEPRECATIONS.md)
124
126
  - [Security Policy](SECURITY.md)
125
127
  - [Threat Model](docs/THREAT_MODEL.md)
@@ -214,7 +216,7 @@ Common asset names:
214
216
  #### Linux
215
217
 
216
218
  ```bash
217
- VERSION="v13.0.1"
219
+ VERSION="v13.1.0"
218
220
  ASSET="cdx-audit-linux-amd64"
219
221
  BASE_URL="https://github.com/cdxgen/cdxgen/releases/download/${VERSION}"
220
222
 
@@ -228,7 +230,7 @@ chmod +x "${ASSET}"
228
230
  #### macOS
229
231
 
230
232
  ```bash
231
- VERSION="v13.0.1"
233
+ VERSION="v13.1.0"
232
234
  ASSET="cdx-audit-darwin-arm64"
233
235
  BASE_URL="https://github.com/cdxgen/cdxgen/releases/download/${VERSION}"
234
236
 
@@ -242,7 +244,7 @@ chmod +x "${ASSET}"
242
244
  #### Windows (PowerShell)
243
245
 
244
246
  ```powershell
245
- $Version = "v13.0.1"
247
+ $Version = "v13.1.0"
246
248
  $Asset = "cdx-audit-windows-amd64.exe"
247
249
  $BaseUrl = "https://github.com/cdxgen/cdxgen/releases/download/$Version"
248
250
 
@@ -267,7 +269,7 @@ steps:
267
269
  env:
268
270
  GH_TOKEN: ${{ github.token }}
269
271
  run: |
270
- gh release download v13.0.1 \
272
+ gh release download v13.1.0 \
271
273
  --repo cdxgen/cdxgen \
272
274
  --pattern 'cdx-audit-linux-amd64' \
273
275
  --pattern 'cdx-audit-linux-amd64.sha256'
@@ -620,6 +622,17 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
620
622
  pnpm dlx @cdxgen/cdxgen-plugins-bin
621
623
  ```
622
624
 
625
+ ## Claude Code plugin
626
+
627
+ The cdxgen toolkit is also packaged as a [Claude Code](https://claude.com/claude-code) plugin, so agents drive the correct command and flags — including the dry-run-first and no-auto-install safety constraints — instead of guessing.
628
+
629
+ ```shell
630
+ claude plugin marketplace add cdxgen/cdxgen
631
+ claude plugin install cdxgen@cdxgen-plugins
632
+ ```
633
+
634
+ It ships skills covering SBOM generation, container and rootfs scans, OBOM/HBOM, CBOM, AI-BOM and MCP inventory, BOM auditing, signing, validation, conversion, evidence enrichment, runtime tracing, and Dependency-Track publishing. See [claude-plugin/README.md](claude-plugin/README.md).
635
+
623
636
  ## Rust accelerator (cdxrs)
624
637
 
625
638
  cdxgen ships with an optional Rust accelerator binary, `cdxrs`, which speeds up hot paths such as registry metadata lookups where available. Use the `--rust` and `--no-rust` arguments to toggle it, or set the environment variable `CDXGEN_RS_DISABLE=all` to force the JavaScript path. See the [cdxrs protocol](./docs/CDXRS_PROTOCOL.md) document for implementation details.
package/bin/audit.js CHANGED
@@ -132,6 +132,11 @@ const args = yargs(hideBin(process.argv))
132
132
  "Path to a license compliance policy YAML file. Evaluates every component license in the BOM(s) and reports prohibited and warning-level violations as a separate table. Error-level (prohibited) violations cause a non-zero exit.",
133
133
  type: "string",
134
134
  })
135
+ .option("introspect", {
136
+ description:
137
+ "Include a build-fidelity introspection verdict for each audited BOM. The BOM was not generated by this run, so the verdict rests on BOM structure alone.",
138
+ type: "boolean",
139
+ })
135
140
  .check((argv) => {
136
141
  if (!argv.bom && !argv.bomDir) {
137
142
  throw new Error("Specify --bom or --bom-dir.");
@@ -204,6 +209,7 @@ function writeOrPrint(output, outputPath) {
204
209
  categories: splitCsv(args.categories),
205
210
  directBomAudit: args.directBomAudit,
206
211
  failSeverity: args.failSeverity,
212
+ introspect: args.introspect === true,
207
213
  licensePolicy: args.licensePolicy,
208
214
  maxTargets: args.maxTargets,
209
215
  minSeverity: args.minSeverity,
package/bin/cdxgen.js CHANGED
@@ -4,6 +4,7 @@ import crypto from "node:crypto";
4
4
  import fs from "node:fs";
5
5
  import http from "node:http";
6
6
  import https from "node:https";
7
+ import { tmpdir } from "node:os";
7
8
  import {
8
9
  basename,
9
10
  dirname,
@@ -25,6 +26,12 @@ import {
25
26
  validateSpecVersion,
26
27
  } from "../lib/cli/cliOptions.js";
27
28
  import { createBom, submitBom } from "../lib/cli/index.js";
29
+ import { closeLedger } from "../lib/core/buildLedger.js";
30
+ import {
31
+ getDeferredFailures,
32
+ INTROSPECTION_FAILURE_EXIT_CODE,
33
+ isDeferredFailOnError,
34
+ } from "../lib/core/deferredExit.js";
28
35
  import { TRACE_MODE, thoughtEnd, thoughtLog } from "../lib/core/logger.js";
29
36
  import {
30
37
  PROJECT_CONFIG_FILENAMES,
@@ -57,6 +64,7 @@ import {
57
64
  retrieveCdxgenVersion,
58
65
  safeExistsSync,
59
66
  safeMkdirSync,
67
+ safeRmSync,
60
68
  safeSpawnSync,
61
69
  safeWriteSync,
62
70
  setActivityContext,
@@ -486,8 +494,33 @@ const args = _yargs
486
494
  "deep-learning",
487
495
  "ml-deep",
488
496
  "ml-tiny",
497
+ "introspect",
489
498
  ],
490
499
  })
500
+ .option("introspect", {
501
+ type: "boolean",
502
+ description:
503
+ "Reflect on how the build environment limited BOM completeness and write an introspection report. Enabled by --profile introspect or CDXGEN_INTROSPECT=true. Pass --no-introspect to keep it off.",
504
+ })
505
+ .option("introspect-report", {
506
+ description:
507
+ "Path for the markdown introspection report. Defaults to <output>.introspection.md; '-' writes the report to stderr.",
508
+ })
509
+ .option("introspect-json", {
510
+ description:
511
+ "Path for the JSON introspection report consumed by remediation loops. Defaults to <output>.introspection.json.",
512
+ })
513
+ .option("introspect-fail-below", {
514
+ type: "number",
515
+ description:
516
+ "CI gate: exit with status 4 after the BOM is written when the overall introspection score is below this 0-100 threshold. Absent means the gate never fails.",
517
+ })
518
+ .option("introspect-annotate", {
519
+ type: "boolean",
520
+ default: true,
521
+ description:
522
+ "Carry the introspection verdict inside the BOM as metadata properties and annotations. Enabled with --introspect; pass --no-introspect-annotate to keep the BOM untouched.",
523
+ })
491
524
  .option("lifecycle", {
492
525
  description: "Product lifecycle for the generated BOM.",
493
526
  hidden: true,
@@ -602,6 +635,7 @@ const args = _yargs
602
635
  "suggest-build-tools",
603
636
  "ruby-docker-install",
604
637
  "resolve-gradle-distribution",
638
+ "jvm-tool-setup",
605
639
  ],
606
640
  })
607
641
  .option("min-confidence", {
@@ -1010,6 +1044,29 @@ const { options, warnings: phase3Warnings } = buildOptionsFromArgs(args, {
1010
1044
  isDryRun,
1011
1045
  isSecureMode,
1012
1046
  });
1047
+ // Exit status reserved for the introspection CI gate: the BOM was generated
1048
+ // and written, but its introspection score missed the configured threshold.
1049
+ // Distinct from 1 so CI can tell a generation failure from a not-good-enough
1050
+ // SBOM.
1051
+ const INTROSPECTION_GATE_EXIT_CODE = 4;
1052
+ // The ledger recorder resolves its environment lazily, so the parsed flag is
1053
+ // bridged into the environment it reads: a run started with --introspect
1054
+ // records the same events as one started with CDXGEN_INTROSPECT=true. Without
1055
+ // an explicitly configured sidecar, an automatic temp sidecar captures
1056
+ // worker-thread events the main thread never sees; it is removed once the
1057
+ // reports are written. Dry-run creates no files, so it keeps an in-memory
1058
+ // ledger only.
1059
+ let autoLedgerSidecar;
1060
+ if (options.introspect) {
1061
+ process.env.CDXGEN_INTROSPECT = "true";
1062
+ if (!isDryRun && !readEnvironmentVariable("CDXGEN_INTROSPECT_LEDGER")) {
1063
+ autoLedgerSidecar = join(
1064
+ tmpdir(),
1065
+ `cdxgen-introspect-ledger-${process.pid}.jsonl`,
1066
+ );
1067
+ process.env.CDXGEN_INTROSPECT_LEDGER = autoLedgerSidecar;
1068
+ }
1069
+ }
1013
1070
  const cliActivityProjectType = Array.isArray(options.projectType)
1014
1071
  ? options.projectType.join(",")
1015
1072
  : options.projectType;
@@ -1683,8 +1740,14 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
1683
1740
  prepareEnv(srcDir, options);
1684
1741
  prepPhase.succeed("");
1685
1742
  } catch (err) {
1686
- prepPhase.fail(err);
1687
- throw err;
1743
+ if (isDeferredFailOnError(err)) {
1744
+ // A deep-mode provisioning failure under --fail-on-error: the scan
1745
+ // continues so the run still produces the verdict that explains it.
1746
+ prepPhase.fail("environment preparation failed");
1747
+ } else {
1748
+ prepPhase.fail(err);
1749
+ throw err;
1750
+ }
1688
1751
  }
1689
1752
  }
1690
1753
  thoughtLog("Getting ready to generate the BOM ⚡️.");
@@ -1756,7 +1819,7 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
1756
1819
  {
1757
1820
  const postPhase = defaultUi.phase("Post-processing BOM");
1758
1821
  try {
1759
- bomNSData = postProcess(
1822
+ bomNSData = await postProcess(
1760
1823
  bomNSData,
1761
1824
  { ...options, executeOsQuery },
1762
1825
  srcDir,
@@ -2008,7 +2071,7 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
2008
2071
  dbObjMap,
2009
2072
  evinseOptions,
2010
2073
  );
2011
- const evinseJson = evinserModule.createEvinseFile(
2074
+ const evinseJson = await evinserModule.createEvinseFile(
2012
2075
  sliceArtefacts,
2013
2076
  evinseOptions,
2014
2077
  );
@@ -2147,6 +2210,64 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
2147
2210
  console.log("Try running the command with -t <type> or -r argument");
2148
2211
  }
2149
2212
  }
2213
+ // The reflection consumed the ledger while producing its reports, so an
2214
+ // automatic sidecar can be released and removed. An explicitly configured
2215
+ // sidecar belongs to the user and is left alone.
2216
+ if (autoLedgerSidecar) {
2217
+ closeLedger();
2218
+ try {
2219
+ safeRmSync(autoLedgerSidecar, { force: true });
2220
+ } catch {
2221
+ // Best-effort cleanup of our own temp file: a runtime whose permission
2222
+ // model denies the removal must not fail a run whose BOM and reports
2223
+ // are already written.
2224
+ }
2225
+ }
2226
+ // A --fail-on-error extractor failure on an introspected run was deferred
2227
+ // until the BOM and both reports existed; here it finally claims its
2228
+ // non-zero exit. It outranks the fidelity gate because a failed toolchain is
2229
+ // the more fundamental claim, and the report still carries the gate
2230
+ // decision.
2231
+ const deferredFailures = getDeferredFailures();
2232
+ if (deferredFailures.length) {
2233
+ const reported = new Set();
2234
+ for (const failure of deferredFailures) {
2235
+ const message = `fail-on-error: ${failure.detail} (tool: ${failure.tool}${failure.exitCode !== undefined ? `, exit ${failure.exitCode}` : ""}).`;
2236
+ if (!reported.has(message)) {
2237
+ reported.add(message);
2238
+ console.error(message);
2239
+ }
2240
+ }
2241
+ // Exit 5 is the promise that the outputs exist. A run that failed before
2242
+ // producing any BOM never made that promise and keeps the historical
2243
+ // exit 1, which is what "cdxgen failed to generate a BOM" has always
2244
+ // meant.
2245
+ const wroteBom = Boolean(bomNSData?.bomJson);
2246
+ console.error(
2247
+ wroteBom
2248
+ ? `fail-on-error: ${reported.size} extractor failure(s) were deferred so the BOM and the introspection report could be written; exiting ${INTROSPECTION_FAILURE_EXIT_CODE}.`
2249
+ : "fail-on-error: no BOM was produced, so there is no verdict to report; exiting 1.",
2250
+ );
2251
+ if (cleanup) {
2252
+ cleanupSourceDir(srcDir);
2253
+ }
2254
+ process.exit(wroteBom ? INTROSPECTION_FAILURE_EXIT_CODE : 1);
2255
+ }
2256
+ // The introspection CI gate fires only after the BOM and the reports are
2257
+ // written: a below-threshold score reports a not-good-enough SBOM, never a
2258
+ // lost one.
2259
+ if (
2260
+ bomNSData?.introspectionGate &&
2261
+ bomNSData.introspectionGate.passed === false
2262
+ ) {
2263
+ console.error(
2264
+ `Build introspection: score ${bomNSData.introspectionGate.score} is below the --introspect-fail-below threshold ${bomNSData.introspectionGate.threshold}.`,
2265
+ );
2266
+ if (cleanup) {
2267
+ cleanupSourceDir(srcDir);
2268
+ }
2269
+ process.exit(INTROSPECTION_GATE_EXIT_CODE);
2270
+ }
2150
2271
  thoughtEnd();
2151
2272
  // Automatically submit the bom data
2152
2273
  // biome-ignore lint/suspicious/noDoubleEquals: yargs passes true for empty values
package/bin/evinse.js CHANGED
@@ -338,7 +338,7 @@ ensureCycloneDxInput(args.input);
338
338
  // Analyze the project using atom. Convert package namespaces to purl using the db
339
339
  const sliceArtefacts = await analyzeProject(dbObjMap, args);
340
340
  // Create the SBOM with Evidence
341
- const bomJson = createEvinseFile(sliceArtefacts, args);
341
+ const bomJson = await createEvinseFile(sliceArtefacts, args);
342
342
  // Validate our final SBOM
343
343
  if (!(await validateBom(bomJson))) {
344
344
  process.exit(1);
@@ -119,7 +119,14 @@
119
119
  "projections",
120
120
  "performance",
121
121
  "plugins",
122
- "non-block"
122
+ "non-block",
123
+ "http",
124
+ "grpc",
125
+ "graphql",
126
+ "wsgi",
127
+ "asgi",
128
+ "llm",
129
+ "mcp"
123
130
  ]
124
131
  },
125
132
  "properties": {
@@ -76,6 +76,56 @@
76
76
  "pkg:pypi/langchain",
77
77
  "pkg:pypi/llama",
78
78
  "pkg:pypi/sqlalchemy",
79
+ "pkg:pypi/starlette",
80
+ "pkg:pypi/quart",
81
+ "pkg:pypi/litestar",
82
+ "pkg:pypi/blacksheep",
83
+ "pkg:pypi/robyn",
84
+ "pkg:pypi/connexion",
85
+ "pkg:pypi/werkzeug",
86
+ "pkg:pypi/asgiref",
87
+ "pkg:pypi/djangorestframework",
88
+ "pkg:pypi/scrapy",
89
+ "pkg:pypi/streamlit",
90
+ "pkg:pypi/gradio",
91
+ "pkg:pypi/dash",
92
+ "pkg:pypi/nicegui",
93
+ "pkg:pypi/reflex",
94
+ "pkg:pypi/pydantic",
95
+ "pkg:pypi/sqlmodel",
96
+ "pkg:pypi/tortoise-orm",
97
+ "pkg:pypi/peewee",
98
+ "pkg:pypi/mongoengine",
99
+ "pkg:pypi/beanie",
100
+ "pkg:pypi/marshmallow",
101
+ "pkg:pypi/strawberry-graphql",
102
+ "pkg:pypi/graphene",
103
+ "pkg:pypi/ariadne",
104
+ "pkg:pypi/grpcio",
105
+ "pkg:pypi/thrift",
106
+ "pkg:pypi/mcp",
107
+ "pkg:pypi/fastmcp",
108
+ "pkg:pypi/openai",
109
+ "pkg:pypi/anthropic",
110
+ "pkg:pypi/litellm",
111
+ "pkg:pypi/langgraph",
112
+ "pkg:pypi/haystack-ai",
113
+ "pkg:pypi/autogen",
114
+ "pkg:pypi/pyautogen",
115
+ "pkg:pypi/crewai",
116
+ "pkg:pypi/semantic-kernel",
117
+ "pkg:pypi/transformers",
118
+ "pkg:pypi/sentence-transformers",
119
+ "pkg:pypi/huggingface-hub",
120
+ "pkg:pypi/celery",
121
+ "pkg:pypi/kombu",
122
+ "pkg:pypi/dramatiq",
123
+ "pkg:pypi/huey",
124
+ "pkg:pypi/jinja2",
125
+ "pkg:pypi/mako",
126
+ "pkg:pypi/chameleon",
127
+ "pkg:pypi/genshi",
128
+ "pkg:pypi/twisted",
79
129
  "vibora",
80
130
  "koa",
81
131
  "-sdk",
@@ -214,6 +264,41 @@
214
264
  "pkg:gem/volt",
215
265
  "pkg:gem/trailblazer",
216
266
  "pkg:gem/ramaze",
217
- "pkg:gem/scorched"
267
+ "pkg:gem/scorched",
268
+ "Grpc.AspNetCore",
269
+ "Microsoft.AspNetCore.SignalR",
270
+ "Microsoft.Azure.Functions.Worker",
271
+ "Microsoft.NET.Sdk.Functions",
272
+ "Amazon.Lambda.Core",
273
+ "MassTransit",
274
+ "NServiceBus",
275
+ "MediatR",
276
+ "Rebus",
277
+ "HotChocolate.AspNetCore",
278
+ "GraphQL",
279
+ "Microsoft.AspNetCore.OData",
280
+ "ModelContextProtocol",
281
+ "ModelContextProtocol.AspNetCore",
282
+ "Microsoft.SemanticKernel",
283
+ "Microsoft.Extensions.AI",
284
+ "OpenAI",
285
+ "Azure.AI.OpenAI",
286
+ "Anthropic.SDK",
287
+ "AWSSDK.BedrockRuntime",
288
+ "Hangfire.AspNetCore",
289
+ "Quartz",
290
+ "FastEndpoints",
291
+ "Carter",
292
+ "ServiceStack",
293
+ "Nancy",
294
+ "Microsoft.ML",
295
+ "Microsoft.ML.OnnxRuntime",
296
+ "TorchSharp",
297
+ "LLamaSharp",
298
+ "Qdrant.Client",
299
+ "Milvus.Client",
300
+ "Pinecone.NET",
301
+ "Dapr.AspNetCore",
302
+ "Confluent.Kafka"
218
303
  ]
219
304
  }