@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.
- package/README.md +15 -8
- package/bin/audit.js +7 -4
- package/bin/cdxgen.js +256 -37
- package/bin/convert.js +146 -22
- package/bin/evinse.js +25 -3
- package/bin/repl.js +47 -3
- package/bin/sign.js +211 -34
- package/bin/tracebom.js +18 -6
- package/bin/validate.js +18 -3
- package/bin/verify.js +113 -5
- package/data/behavior-taxonomy.schema.json +1491 -0
- package/data/cyclonedx-2.0-bundled.schema.json +18606 -5528
- package/data/cyclonedx-2.0-cryptography-defs.schema.json +857 -0
- package/data/pqc-migration.json +239 -0
- package/data/remediations.json +52 -0
- package/data/rules/cbom-security.yaml +4 -3
- package/data/rules/package-integrity.yaml +28 -0
- package/lib/audit/index.js +25 -3
- package/lib/cli/bomAssembly.js +80 -1
- package/lib/cli/cliOptions.js +121 -17
- package/lib/cli/index.js +609 -898
- package/lib/cli/jsBom.js +3 -0
- package/lib/cli/jvmBom.js +365 -40
- package/lib/cli/managedBom.js +19 -3
- package/lib/cli/nativeBom.js +10 -0
- package/lib/core/env.js +26 -0
- package/lib/core/fs.js +126 -3
- package/lib/core/globPatterns.js +218 -0
- package/lib/core/processTree.js +99 -12
- package/lib/core/projectConfig.js +332 -25
- package/lib/core/toolRegistry.js +15 -1
- package/lib/ecosystems/denoutils.js +2 -2
- package/lib/ecosystems/golem.js +3 -8
- package/lib/ecosystems/gradleutils.js +1082 -6
- package/lib/ecosystems/jsEvidence.js +90 -38
- package/lib/ecosystems/kosi.js +3 -5
- package/lib/ecosystems/npmVersionResolution.js +376 -0
- package/lib/ecosystems/parsers-python.js +89 -28
- package/lib/ecosystems/parsers-rust.js +117 -15
- package/lib/ecosystems/remote/huggingface.js +22 -0
- package/lib/ecosystems/rusi.js +2 -4
- package/lib/ecosystems/scalasem.js +2 -1
- package/lib/evinser/evinser.js +196 -34
- package/lib/evinser/scalasem.js +5 -1
- package/lib/helpers/agenticToolutils.js +112 -1
- package/lib/helpers/bomSigner.js +43 -9
- package/lib/helpers/jssSigner.js +1276 -0
- package/lib/inventory/agentBlueprint.js +193 -0
- package/lib/inventory/agentToolNames.js +145 -0
- package/lib/inventory/aiCollector.js +153 -7
- package/lib/inventory/aiInventory.js +44 -8
- package/lib/inventory/aiProviders.js +324 -0
- package/lib/inventory/bomUtils.js +8 -1
- package/lib/inventory/ciParsers/githubActionsLock.js +821 -0
- package/lib/inventory/citations.js +31 -2
- package/lib/inventory/communityAiConfigParser.js +978 -80
- package/lib/inventory/cyclonedx20.js +152 -0
- package/lib/inventory/cyclonedx20Common.js +286 -0
- package/lib/inventory/cyclonedx20Derived.js +159 -0
- package/lib/inventory/cyclonedx20Parties.js +552 -0
- package/lib/inventory/cyclonedx20Read.js +768 -0
- package/lib/inventory/cyclonedx20ReadCommon.js +374 -0
- package/lib/inventory/cyclonedx20ReadComponents.js +692 -0
- package/lib/inventory/cyclonedx20ReadContext.js +380 -0
- package/lib/inventory/cyclonedx20ReadEvidence.js +466 -0
- package/lib/inventory/cyclonedx20ReadSections.js +599 -0
- package/lib/inventory/cyclonedx20Render.js +766 -0
- package/lib/inventory/cyclonedx20RenderComponents.js +716 -0
- package/lib/inventory/cyclonedx20RenderDefinitions.js +405 -0
- package/lib/inventory/cyclonedx20RenderEvidence.js +726 -0
- package/lib/inventory/cyclonedx20RenderHardware.js +203 -0
- package/lib/inventory/cyclonedx20RenderPatents.js +174 -0
- package/lib/inventory/cyclonedx20RenderRefIds.js +314 -0
- package/lib/inventory/cyclonedx20RenderSections.js +499 -0
- package/lib/inventory/cyclonedx20Tables.js +594 -0
- package/lib/inventory/deps.js +106 -13
- package/lib/inventory/dosai.js +236 -1
- package/lib/inventory/dosaiParsers.js +3 -6
- package/lib/inventory/dotnetRuntime.js +164 -14
- package/lib/inventory/ecosystemFormulationParsers.js +979 -0
- package/lib/inventory/envcontext.js +132 -38
- package/lib/inventory/evidenceUtils.js +2 -1
- package/lib/inventory/formulationParsers.js +95 -13
- package/lib/inventory/hbom.js +45 -6
- package/lib/inventory/hbomLoader.js +166 -0
- package/lib/inventory/mcpConfigParser.js +5 -0
- package/lib/inventory/occurrenceKey.js +90 -0
- package/lib/inventory/pqcMigration.js +426 -0
- package/lib/inventory/rustFormulationParser.js +21 -10
- package/lib/inventory/source.js +65 -6
- package/lib/parsers/huggingfaceManifest.js +9 -1
- package/lib/parsers/huggingfaceUtils.js +18 -0
- package/lib/parsers/kiroPermissions.js +166 -0
- package/lib/server/server.js +36 -34
- package/lib/stages/postgen/postgen.js +41 -1
- package/lib/stages/postgen/specVersionCompat.js +76 -0
- package/lib/validator/bomValidator.js +8 -1
- package/lib/validator/complianceEngine.js +30 -3
- package/lib/validator/complianceRules.js +1416 -4
- package/lib/validator/generated/validate-2.0.mjs +57554 -13851
- package/lib/validator/index.js +48 -7
- package/lib/validator/reporters/json.js +6 -0
- package/package.json +9 -9
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +6 -2
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +16 -0
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +6 -0
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jsBom.d.ts +2 -1
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +15 -0
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/boundedFile.d.ts +30 -0
- package/types/lib/core/boundedFile.d.ts.map +1 -1
- package/types/lib/core/env.d.ts +10 -0
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts +4 -0
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/globPatterns.d.ts +70 -0
- package/types/lib/core/globPatterns.d.ts.map +1 -0
- package/types/lib/core/paths.d.ts +9 -0
- package/types/lib/core/paths.d.ts.map +1 -1
- package/types/lib/core/processTree.d.ts +16 -5
- package/types/lib/core/processTree.d.ts.map +1 -1
- package/types/lib/core/projectConfig.d.ts +47 -8
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/toolRegistry.d.ts.map +1 -1
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +248 -8
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts +14 -1
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts.map +1 -1
- package/types/lib/ecosystems/npmVersionResolution.d.ts +119 -0
- package/types/lib/ecosystems/npmVersionResolution.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +1 -1
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/ecosystems/scalasem.d.ts +58 -16
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +61 -9
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/scalasem.d.ts.map +1 -1
- package/types/lib/helpers/agenticToolutils.d.ts +53 -19
- package/types/lib/helpers/agenticToolutils.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +20 -3
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/helpers/jssSigner.d.ts +288 -0
- package/types/lib/helpers/jssSigner.d.ts.map +1 -0
- package/types/lib/helpers/vsixutils.d.ts +303 -19
- package/types/lib/helpers/vsixutils.d.ts.map +1 -1
- package/types/lib/inventory/agentBlueprint.d.ts +70 -0
- package/types/lib/inventory/agentBlueprint.d.ts.map +1 -0
- package/types/lib/inventory/agentToolNames.d.ts +51 -0
- package/types/lib/inventory/agentToolNames.d.ts.map +1 -0
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/aiInventory.d.ts.map +1 -1
- package/types/lib/inventory/aiProviders.d.ts +85 -0
- package/types/lib/inventory/aiProviders.d.ts.map +1 -0
- package/types/lib/inventory/bomUtils.d.ts.map +1 -1
- package/types/lib/inventory/ciParsers/githubActionsLock.d.ts +101 -0
- package/types/lib/inventory/ciParsers/githubActionsLock.d.ts.map +1 -0
- package/types/lib/inventory/citations.d.ts +5 -0
- package/types/lib/inventory/citations.d.ts.map +1 -1
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/cyclonedx20.d.ts +99 -0
- package/types/lib/inventory/cyclonedx20.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Common.d.ts +102 -0
- package/types/lib/inventory/cyclonedx20Common.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Derived.d.ts +74 -0
- package/types/lib/inventory/cyclonedx20Derived.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Parties.d.ts +91 -0
- package/types/lib/inventory/cyclonedx20Parties.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Read.d.ts +51 -0
- package/types/lib/inventory/cyclonedx20Read.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadCommon.d.ts +69 -0
- package/types/lib/inventory/cyclonedx20ReadCommon.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadComponents.d.ts +77 -0
- package/types/lib/inventory/cyclonedx20ReadComponents.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadContext.d.ts +118 -0
- package/types/lib/inventory/cyclonedx20ReadContext.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts +40 -0
- package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadSections.d.ts +45 -0
- package/types/lib/inventory/cyclonedx20ReadSections.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Render.d.ts +53 -0
- package/types/lib/inventory/cyclonedx20Render.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderComponents.d.ts +73 -0
- package/types/lib/inventory/cyclonedx20RenderComponents.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts +29 -0
- package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts +110 -0
- package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderHardware.d.ts +42 -0
- package/types/lib/inventory/cyclonedx20RenderHardware.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderPatents.d.ts +26 -0
- package/types/lib/inventory/cyclonedx20RenderPatents.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts +55 -0
- package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderSections.d.ts +45 -0
- package/types/lib/inventory/cyclonedx20RenderSections.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Tables.d.ts +134 -0
- package/types/lib/inventory/cyclonedx20Tables.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +35 -2
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +19 -0
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
- package/types/lib/inventory/dotnetRuntime.d.ts +51 -4
- package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -1
- package/types/lib/inventory/ecosystemFormulationParsers.d.ts +73 -0
- package/types/lib/inventory/ecosystemFormulationParsers.d.ts.map +1 -0
- package/types/lib/inventory/envcontext.d.ts +22 -6
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
- package/types/lib/inventory/hbom.d.ts +11 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -1
- package/types/lib/inventory/hbomLoader.d.ts +54 -0
- package/types/lib/inventory/hbomLoader.d.ts.map +1 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts +5 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -1
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/occurrenceKey.d.ts +52 -0
- package/types/lib/inventory/occurrenceKey.d.ts.map +1 -0
- package/types/lib/inventory/pqcMigration.d.ts +84 -0
- package/types/lib/inventory/pqcMigration.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts +7 -2
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/scalaCoords.d.ts.map +1 -1
- package/types/lib/inventory/scalaDedupe.d.ts +43 -0
- package/types/lib/inventory/scalaDedupe.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +15 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/parsers/huggingfaceManifest.d.ts +10 -1
- package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -1
- package/types/lib/parsers/huggingfaceUtils.d.ts +12 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
- package/types/lib/parsers/kiroPermissions.d.ts +62 -0
- package/types/lib/parsers/kiroPermissions.d.ts.map +1 -0
- package/types/lib/parsers/vscodeExtensionId.d.ts +48 -0
- package/types/lib/parsers/vscodeExtensionId.d.ts.map +1 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +7 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts +25 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts +5 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/complianceEngine.d.ts +4 -4
- package/types/lib/validator/complianceEngine.d.ts.map +1 -1
- package/types/lib/validator/complianceRules.d.ts +14 -2
- package/types/lib/validator/complianceRules.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +10 -0
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -121,7 +121,9 @@ Sections include:
|
|
|
121
121
|
- [MCP Inventory](docs/MCP.md)
|
|
122
122
|
- [REPL Guide](docs/REPL.md)
|
|
123
123
|
- [Custom Properties](docs/CUSTOM_PROPERTIES.md)
|
|
124
|
-
- [
|
|
124
|
+
- [Coding Agent Plugin](agent-plugin/README.md)
|
|
125
|
+
- [Installing the plugin in coding agents](docs/AGENT_PLUGINS.md)
|
|
126
|
+
- [Agent CI recipes](docs/AGENT_CI.md)
|
|
125
127
|
- [Deprecations](docs/DEPRECATIONS.md)
|
|
126
128
|
- [Security Policy](SECURITY.md)
|
|
127
129
|
- [Threat Model](docs/THREAT_MODEL.md)
|
|
@@ -216,7 +218,7 @@ Common asset names:
|
|
|
216
218
|
#### Linux
|
|
217
219
|
|
|
218
220
|
```bash
|
|
219
|
-
VERSION="v13.
|
|
221
|
+
VERSION="v13.7.0"
|
|
220
222
|
ASSET="cdx-audit-linux-amd64"
|
|
221
223
|
BASE_URL="https://github.com/cdxgen/cdxgen/releases/download/${VERSION}"
|
|
222
224
|
|
|
@@ -230,7 +232,7 @@ chmod +x "${ASSET}"
|
|
|
230
232
|
#### macOS
|
|
231
233
|
|
|
232
234
|
```bash
|
|
233
|
-
VERSION="v13.
|
|
235
|
+
VERSION="v13.7.0"
|
|
234
236
|
ASSET="cdx-audit-darwin-arm64"
|
|
235
237
|
BASE_URL="https://github.com/cdxgen/cdxgen/releases/download/${VERSION}"
|
|
236
238
|
|
|
@@ -244,7 +246,7 @@ chmod +x "${ASSET}"
|
|
|
244
246
|
#### Windows (PowerShell)
|
|
245
247
|
|
|
246
248
|
```powershell
|
|
247
|
-
$Version = "v13.
|
|
249
|
+
$Version = "v13.7.0"
|
|
248
250
|
$Asset = "cdx-audit-windows-amd64.exe"
|
|
249
251
|
$BaseUrl = "https://github.com/cdxgen/cdxgen/releases/download/$Version"
|
|
250
252
|
|
|
@@ -269,7 +271,7 @@ steps:
|
|
|
269
271
|
env:
|
|
270
272
|
GH_TOKEN: ${{ github.token }}
|
|
271
273
|
run: |
|
|
272
|
-
gh release download v13.
|
|
274
|
+
gh release download v13.7.0 \
|
|
273
275
|
--repo cdxgen/cdxgen \
|
|
274
276
|
--pattern 'cdx-audit-linux-amd64' \
|
|
275
277
|
--pattern 'cdx-audit-linux-amd64.sha256'
|
|
@@ -621,16 +623,21 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
|
|
|
621
623
|
pnpm dlx @cdxgen/cdxgen-plugins-bin
|
|
622
624
|
```
|
|
623
625
|
|
|
624
|
-
##
|
|
626
|
+
## Coding agent plugin
|
|
625
627
|
|
|
626
|
-
The cdxgen toolkit is also packaged as a
|
|
628
|
+
The cdxgen toolkit is also packaged as a plugin for coding agents, so agents drive the correct command and flags, including the dry-run-first and no-auto-install safety constraints, instead of guessing. It is meant for Claude Code, OpenAI Codex, the GitHub Copilot CLI and app, Cursor, Gemini CLI, Kiro and opencode, and has been tried in Claude Code and Codex so far.
|
|
627
629
|
|
|
628
630
|
```shell
|
|
629
631
|
claude plugin marketplace add cdxgen/cdxgen
|
|
630
632
|
claude plugin install cdxgen@cdxgen-plugins
|
|
631
633
|
```
|
|
632
634
|
|
|
633
|
-
|
|
635
|
+
```shell
|
|
636
|
+
codex plugin marketplace add cdxgen/cdxgen
|
|
637
|
+
codex plugin add cdxgen@cdxgen-plugins
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
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 [agent-plugin/README.md](agent-plugin/README.md) and the [installation guide](docs/AGENT_PLUGINS.md) for each client. To run cdxgen through an agent in GitHub Actions, see the [agent CI recipes](docs/AGENT_CI.md).
|
|
634
641
|
|
|
635
642
|
## Rust accelerator (cdxrs)
|
|
636
643
|
|
package/bin/audit.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { writeFileSync } from "node:fs";
|
|
4
3
|
import { dirname } from "node:path";
|
|
5
4
|
import process from "node:process";
|
|
6
5
|
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
retrieveCdxgenVersion,
|
|
14
13
|
safeExistsSync,
|
|
15
14
|
safeMkdirSync,
|
|
15
|
+
safeWriteSync,
|
|
16
16
|
} from "../lib/ecosystems/utils.js";
|
|
17
17
|
|
|
18
18
|
const args = yargs(hideBin(process.argv))
|
|
@@ -193,7 +193,7 @@ function writeOrPrint(output, outputPath) {
|
|
|
193
193
|
if (!safeExistsSync(parentDir)) {
|
|
194
194
|
safeMkdirSync(parentDir, { recursive: true });
|
|
195
195
|
}
|
|
196
|
-
|
|
196
|
+
safeWriteSync(outputPath, output);
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
(async () => {
|
|
@@ -235,10 +235,13 @@ function writeOrPrint(output, outputPath) {
|
|
|
235
235
|
report: args.report,
|
|
236
236
|
});
|
|
237
237
|
writeOrPrint(finalized.output, reportFile);
|
|
238
|
-
process.exit
|
|
238
|
+
// exitCode instead of process.exit lets a piped stdout write drain before
|
|
239
|
+
// the process ends, and the finally block below still runs.
|
|
240
|
+
process.exitCode = finalized.exitCode;
|
|
239
241
|
} catch (error) {
|
|
240
242
|
console.error(error.message);
|
|
241
|
-
process.exit
|
|
243
|
+
// exitCode instead of process.exit lets pending stderr output drain.
|
|
244
|
+
process.exitCode = 1;
|
|
242
245
|
} finally {
|
|
243
246
|
progressTracker.stop();
|
|
244
247
|
}
|
package/bin/cdxgen.js
CHANGED
|
@@ -83,13 +83,24 @@ import {
|
|
|
83
83
|
createOutputPlan,
|
|
84
84
|
getOutputDirectory,
|
|
85
85
|
} from "../lib/helpers/exportUtils.js";
|
|
86
|
+
import {
|
|
87
|
+
generateJssKeyPair,
|
|
88
|
+
signJssBom,
|
|
89
|
+
verifyJssBom,
|
|
90
|
+
} from "../lib/helpers/jssSigner.js";
|
|
86
91
|
import {
|
|
87
92
|
DEFAULT_CDX_SPEC_VERSION,
|
|
88
93
|
getSupportedCycloneDxComponentTypes,
|
|
94
|
+
isCycloneDx20SpecVersion,
|
|
89
95
|
isCycloneDxBom,
|
|
90
96
|
normalizeCycloneDxComponentTypeFilter,
|
|
91
97
|
toCycloneDxSpecVersionString,
|
|
92
98
|
} from "../lib/inventory/bomUtils.js";
|
|
99
|
+
import {
|
|
100
|
+
DEPENDENCY_TRACK_CDX20_ERROR,
|
|
101
|
+
getInternalBom,
|
|
102
|
+
refreshRenderedBom,
|
|
103
|
+
} from "../lib/inventory/cyclonedx20.js";
|
|
93
104
|
import {
|
|
94
105
|
displaySelfThreatModel,
|
|
95
106
|
printActivitySummary,
|
|
@@ -155,16 +166,37 @@ for (const configPattern of PROJECT_CONFIG_FILENAMES) {
|
|
|
155
166
|
continue;
|
|
156
167
|
}
|
|
157
168
|
try {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
169
|
+
const parsedConfig =
|
|
170
|
+
configPath.endsWith(".yml") || configPath.endsWith(".yaml")
|
|
171
|
+
? _load(fs.readFileSync(configPath, "utf-8"))
|
|
172
|
+
: JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
163
173
|
if (isSecureMode || DEBUG_MODE) {
|
|
164
174
|
console.log(`Config file '${configPath}' loaded successfully.`);
|
|
165
175
|
}
|
|
166
|
-
const sanitized = sanitizeProjectConfig(
|
|
176
|
+
const sanitized = sanitizeProjectConfig(parsedConfig, dirname(configPath));
|
|
167
177
|
config = sanitized.config;
|
|
178
|
+
for (const key of sanitized.operatorOnly) {
|
|
179
|
+
console.warn(
|
|
180
|
+
`\x1b[1;35mConfig file '${configPath}' sets '${key}', which only the command line or a CDXGEN_ environment variable may set. Ignoring it.\x1b[0m`,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
for (const projectType of sanitized.hostScopeTypes) {
|
|
184
|
+
console.warn(
|
|
185
|
+
`\x1b[1;35mConfig file '${configPath}' selects the project type '${projectType}', which inventories this host rather than the project. Ignoring it. Pass '-t ${projectType}' on the command line if this is intentional.\x1b[0m`,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
for (const key of sanitized.ignored) {
|
|
189
|
+
console.warn(
|
|
190
|
+
`Config file '${configPath}' sets '${key}', which is not an option a config file can set. Ignoring it.`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
for (const { key, pattern, reason } of sanitized.refusedPatterns) {
|
|
194
|
+
const shownPattern =
|
|
195
|
+
pattern.length > 80 ? `${pattern.slice(0, 77)}...` : pattern;
|
|
196
|
+
console.warn(
|
|
197
|
+
`\x1b[1;35mConfig file '${configPath}' sets the ${key} pattern '${shownPattern}', which ${reason}. Ignoring it. Pass the pattern on the command line if this is intentional.\x1b[0m`,
|
|
198
|
+
);
|
|
199
|
+
}
|
|
168
200
|
for (const entry of sanitized.rejected) {
|
|
169
201
|
console.warn(
|
|
170
202
|
`\x1b[1;35mConfig file '${configPath}' sets '${entry}', which points outside the project directory. Ignoring it. Pass the option on the command line if this is intentional.\x1b[0m`,
|
|
@@ -425,7 +457,7 @@ const args = _yargs
|
|
|
425
457
|
.option("generate-key-and-sign", {
|
|
426
458
|
type: "boolean",
|
|
427
459
|
description:
|
|
428
|
-
"Generate a public/private key pair for SBOM_SIGN_ALGORITHM
|
|
460
|
+
"Generate a public/private key pair for SBOM_SIGN_ALGORITHM and then sign the generated SBOM: with the JSON Signature Format (JSF, RS512 by default) at 1.x, or the JSON Signature Scheme (JSS, ITU-T X.590; Ed25519 by default) at --spec-version 2.0.",
|
|
429
461
|
})
|
|
430
462
|
.option("server", {
|
|
431
463
|
type: "boolean",
|
|
@@ -634,7 +666,7 @@ const args = _yargs
|
|
|
634
666
|
type: "boolean",
|
|
635
667
|
default: false,
|
|
636
668
|
description:
|
|
637
|
-
"Generate formulation section with git metadata and build
|
|
669
|
+
"Generate formulation section with git metadata, build tools and build inputs. On by default when CI=true, for BOM audits, the research and introspect profiles, OS project types and the cbom command; --no-include-formulation turns it off.",
|
|
638
670
|
})
|
|
639
671
|
.option("include-crypto", {
|
|
640
672
|
type: "boolean",
|
|
@@ -697,6 +729,8 @@ const args = _yargs
|
|
|
697
729
|
"suggest-build-tools",
|
|
698
730
|
"ruby-docker-install",
|
|
699
731
|
"resolve-gradle-distribution",
|
|
732
|
+
"gradle-prefer-lockfile",
|
|
733
|
+
"gradle-verification-fallback",
|
|
700
734
|
"jvm-tool-setup",
|
|
701
735
|
],
|
|
702
736
|
})
|
|
@@ -1208,6 +1242,21 @@ try {
|
|
|
1208
1242
|
console.error(error.message);
|
|
1209
1243
|
process.exit(1);
|
|
1210
1244
|
}
|
|
1245
|
+
// Dependency-Track ingests CycloneDX 1.x only. Refuse an upload (server URL
|
|
1246
|
+
// plus API key, the same condition the submission below uses) before
|
|
1247
|
+
// generating, so a long scan does not end in an upload that cannot succeed.
|
|
1248
|
+
// Server mode checks each request instead, since a request may choose its own
|
|
1249
|
+
// version.
|
|
1250
|
+
if (
|
|
1251
|
+
!options.server &&
|
|
1252
|
+
typeof options.serverUrl === "string" &&
|
|
1253
|
+
options.serverUrl.length > 0 &&
|
|
1254
|
+
options.apiKey &&
|
|
1255
|
+
isCycloneDx20SpecVersion(options.specVersion)
|
|
1256
|
+
) {
|
|
1257
|
+
console.error(DEPENDENCY_TRACK_CDX20_ERROR);
|
|
1258
|
+
process.exit(1);
|
|
1259
|
+
}
|
|
1211
1260
|
if (!options.projectType) {
|
|
1212
1261
|
thoughtLog(
|
|
1213
1262
|
"Ok, the user wants me to identify all the project types and generate a consolidated BOM document.",
|
|
@@ -1280,6 +1329,7 @@ if (options.lifecycle) {
|
|
|
1280
1329
|
const isHbomOnlyInvocation = isHbomOnlyProjectTypes(options.projectType);
|
|
1281
1330
|
const advancedWarnings = applyAdvancedOptionsImpl(options, {
|
|
1282
1331
|
isSecureMode: isSecureModeActive(),
|
|
1332
|
+
invokedCommandName,
|
|
1283
1333
|
});
|
|
1284
1334
|
// The config file comes from the working directory, usually the scanned
|
|
1285
1335
|
// project, so whether the project's own code may run stays the operator's
|
|
@@ -1644,6 +1694,99 @@ const signCycloneDxPayload = (jsonPayload, keyDir, target, options) => {
|
|
|
1644
1694
|
return signedBom;
|
|
1645
1695
|
};
|
|
1646
1696
|
|
|
1697
|
+
/**
|
|
1698
|
+
* Signs a CycloneDX 2.0 payload with JSS (ITU-T X.590) using the configured
|
|
1699
|
+
* or generated key: the root and the nested members the draft allows (see
|
|
1700
|
+
* lib/helpers/jssSigner.js). A generated key is checked against the fresh
|
|
1701
|
+
* signature, as the JSF path does.
|
|
1702
|
+
*
|
|
1703
|
+
* @param {string} jsonPayload Serialized CycloneDX 2.0 BOM
|
|
1704
|
+
* @param {string|undefined} keyDir Directory for --generate-key-and-sign keys
|
|
1705
|
+
* @param {string} target Output the signed BOM is written to (for the activity log)
|
|
1706
|
+
* @param {Object} options CLI options
|
|
1707
|
+
* @returns {Object} Signed BOM
|
|
1708
|
+
* @throws {Error} When signing was requested but cannot be completed
|
|
1709
|
+
*/
|
|
1710
|
+
const signJssPayload = (jsonPayload, keyDir, target, options) => {
|
|
1711
|
+
// Signing a supplied key needs SBOM_SIGN_ALGORITHM (see needsBomSigning);
|
|
1712
|
+
// only --generate-key-and-sign reaches here without one.
|
|
1713
|
+
const algorithm = readEnvironmentVariable("SBOM_SIGN_ALGORITHM") || "Ed25519";
|
|
1714
|
+
const sbomSignPrivateKey = readEnvironmentVariable("SBOM_SIGN_PRIVATE_KEY", {
|
|
1715
|
+
sensitive: true,
|
|
1716
|
+
});
|
|
1717
|
+
const sbomSignPrivateKeyBase64 = readEnvironmentVariable(
|
|
1718
|
+
"SBOM_SIGN_PRIVATE_KEY_BASE64",
|
|
1719
|
+
{ sensitive: true },
|
|
1720
|
+
);
|
|
1721
|
+
let privateKey;
|
|
1722
|
+
let publicKeyFile;
|
|
1723
|
+
if (options.generateKeyAndSign) {
|
|
1724
|
+
if (!keyDir) {
|
|
1725
|
+
throw new Error(
|
|
1726
|
+
"--generate-key-and-sign needs a file output (-o) to write the generated keys next to.",
|
|
1727
|
+
);
|
|
1728
|
+
}
|
|
1729
|
+
publicKeyFile = join(keyDir, "public.key");
|
|
1730
|
+
const privateKeyFile = join(keyDir, "private.key");
|
|
1731
|
+
const generated = generateJssKeyPair(algorithm);
|
|
1732
|
+
safeWriteSync(
|
|
1733
|
+
publicKeyFile,
|
|
1734
|
+
generated.publicKey.export({ type: "spki", format: "pem" }),
|
|
1735
|
+
);
|
|
1736
|
+
// The private key is readable by the owner only.
|
|
1737
|
+
safeWriteSync(
|
|
1738
|
+
privateKeyFile,
|
|
1739
|
+
generated.privateKey.export({ type: "pkcs8", format: "pem" }),
|
|
1740
|
+
{ mode: 0o600 },
|
|
1741
|
+
);
|
|
1742
|
+
console.log(
|
|
1743
|
+
"Created public/private key pairs for testing purposes",
|
|
1744
|
+
publicKeyFile,
|
|
1745
|
+
privateKeyFile,
|
|
1746
|
+
);
|
|
1747
|
+
privateKey = generated.privateKey;
|
|
1748
|
+
} else if (sbomSignPrivateKey) {
|
|
1749
|
+
if (!safeExistsSync(sbomSignPrivateKey)) {
|
|
1750
|
+
throw new Error(
|
|
1751
|
+
`The SBOM_SIGN_PRIVATE_KEY file '${sbomSignPrivateKey}' was not found.`,
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
recordSensitiveFileRead(sbomSignPrivateKey, {
|
|
1755
|
+
label: "SBOM signing private key",
|
|
1756
|
+
});
|
|
1757
|
+
privateKey = fs.readFileSync(sbomSignPrivateKey);
|
|
1758
|
+
} else if (sbomSignPrivateKeyBase64) {
|
|
1759
|
+
privateKey = Buffer.from(sbomSignPrivateKeyBase64, "base64");
|
|
1760
|
+
} else {
|
|
1761
|
+
throw new Error(
|
|
1762
|
+
`Signing a CycloneDX 2.0 document needs a private key: set SBOM_SIGN_PRIVATE_KEY (PEM), SBOM_SIGN_PRIVATE_KEY_BASE64, or pass --generate-key-and-sign. Algorithm in use: ${algorithm}.`,
|
|
1763
|
+
);
|
|
1764
|
+
}
|
|
1765
|
+
thoughtLog(`Signing the BOM for "${target}" with JSS (${algorithm}).`);
|
|
1766
|
+
const signedBom = signJssBom(JSON.parse(jsonPayload), {
|
|
1767
|
+
algorithm,
|
|
1768
|
+
privateKey,
|
|
1769
|
+
});
|
|
1770
|
+
if (publicKeyFile) {
|
|
1771
|
+
const verdict = verifyJssBom(signedBom, {
|
|
1772
|
+
publicKey: fs.readFileSync(publicKeyFile, "utf8"),
|
|
1773
|
+
requireAll: true,
|
|
1774
|
+
});
|
|
1775
|
+
if (!verdict.valid) {
|
|
1776
|
+
throw new Error(
|
|
1777
|
+
`The new JSS signature does not verify with ${publicKeyFile}.`,
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1780
|
+
console.log(
|
|
1781
|
+
"SBOM signature is verifiable natively with the public key and the algorithm",
|
|
1782
|
+
publicKeyFile,
|
|
1783
|
+
algorithm,
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
recordActivity({ kind: "sign", status: "completed", target });
|
|
1787
|
+
return signedBom;
|
|
1788
|
+
};
|
|
1789
|
+
|
|
1647
1790
|
/**
|
|
1648
1791
|
* Signs the BOM for an output when signing is configured. A failure is
|
|
1649
1792
|
* recorded and returned so that the caller can stop with a non-zero exit
|
|
@@ -1664,6 +1807,24 @@ const signForOutput = (bomJson, jsonPayload, keyDir, target, options) => {
|
|
|
1664
1807
|
});
|
|
1665
1808
|
return { bomJson, jsonPayload };
|
|
1666
1809
|
}
|
|
1810
|
+
if (isCycloneDx20SpecVersion(bomJson?.specVersion || options?.specVersion)) {
|
|
1811
|
+
// A CycloneDX 2.0 document signs with JSS (ITU-T X.590) instead of JSF.
|
|
1812
|
+
try {
|
|
1813
|
+
const signedBom = signJssPayload(jsonPayload, keyDir, target, options);
|
|
1814
|
+
return {
|
|
1815
|
+
bomJson: signedBom,
|
|
1816
|
+
jsonPayload: stringifyJson(signedBom, options.jsonPretty),
|
|
1817
|
+
};
|
|
1818
|
+
} catch (err) {
|
|
1819
|
+
recordActivity({
|
|
1820
|
+
kind: "sign",
|
|
1821
|
+
reason: err.message,
|
|
1822
|
+
status: "failed",
|
|
1823
|
+
target,
|
|
1824
|
+
});
|
|
1825
|
+
return { bomJson, jsonPayload, signingError: err };
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1667
1828
|
try {
|
|
1668
1829
|
const signedBom = signCycloneDxPayload(
|
|
1669
1830
|
jsonPayload,
|
|
@@ -2002,7 +2163,10 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2002
2163
|
hasCriticalFindings,
|
|
2003
2164
|
} = await import("../lib/stages/postgen/auditBom.js");
|
|
2004
2165
|
thoughtLog("Let's run security audit...");
|
|
2005
|
-
|
|
2166
|
+
// The audit and its annotations read the 1.x-shaped model; at 2.0 the
|
|
2167
|
+
// rendered document is refreshed once after the last mutation.
|
|
2168
|
+
const auditInternalBom = getInternalBom(bomNSData);
|
|
2169
|
+
const postAuditFindings = await auditBom(auditInternalBom, {
|
|
2006
2170
|
...options,
|
|
2007
2171
|
getBomWithOras,
|
|
2008
2172
|
});
|
|
@@ -2021,9 +2185,9 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2021
2185
|
}
|
|
2022
2186
|
}
|
|
2023
2187
|
if (postAuditFindings.length && options.specVersion >= 1.4) {
|
|
2024
|
-
|
|
2025
|
-
...(
|
|
2026
|
-
...formatAnnotations(postAuditFindings,
|
|
2188
|
+
auditInternalBom.annotations = [
|
|
2189
|
+
...(auditInternalBom.annotations || []),
|
|
2190
|
+
...formatAnnotations(postAuditFindings, auditInternalBom),
|
|
2027
2191
|
];
|
|
2028
2192
|
thoughtLog(
|
|
2029
2193
|
`Embedded ${postAuditFindings.length} audit findings as CycloneDX annotations`,
|
|
@@ -2057,7 +2221,7 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2057
2221
|
const requiredAuditTargetCount = collectAuditTargets(
|
|
2058
2222
|
[
|
|
2059
2223
|
{
|
|
2060
|
-
bomJson:
|
|
2224
|
+
bomJson: auditInternalBom,
|
|
2061
2225
|
source: filePath,
|
|
2062
2226
|
},
|
|
2063
2227
|
],
|
|
@@ -2078,7 +2242,7 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2078
2242
|
predictiveReport = await runAuditFromBoms(
|
|
2079
2243
|
[
|
|
2080
2244
|
{
|
|
2081
|
-
bomJson:
|
|
2245
|
+
bomJson: auditInternalBom,
|
|
2082
2246
|
source: filePath,
|
|
2083
2247
|
},
|
|
2084
2248
|
],
|
|
@@ -2115,14 +2279,14 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2115
2279
|
}
|
|
2116
2280
|
const predictiveAnnotations = formatPredictiveAnnotations(
|
|
2117
2281
|
predictiveReport,
|
|
2118
|
-
|
|
2282
|
+
auditInternalBom,
|
|
2119
2283
|
{
|
|
2120
2284
|
minSeverity: options.bomAuditMinSeverity,
|
|
2121
2285
|
},
|
|
2122
2286
|
);
|
|
2123
2287
|
if (predictiveAnnotations.length && options.specVersion >= 1.4) {
|
|
2124
|
-
|
|
2125
|
-
...(
|
|
2288
|
+
auditInternalBom.annotations = [
|
|
2289
|
+
...(auditInternalBom.annotations || []),
|
|
2126
2290
|
...predictiveAnnotations,
|
|
2127
2291
|
];
|
|
2128
2292
|
thoughtLog(
|
|
@@ -2165,9 +2329,11 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2165
2329
|
target: internalCycloneDxInputPath,
|
|
2166
2330
|
});
|
|
2167
2331
|
} else {
|
|
2332
|
+
// Evinse reads and writes the 1.x shape, so the temp input is the
|
|
2333
|
+
// internal model, not the rendered 2.0 document.
|
|
2168
2334
|
safeWriteSync(
|
|
2169
2335
|
internalCycloneDxInputPath,
|
|
2170
|
-
stringifyJson(bomNSData
|
|
2336
|
+
stringifyJson(getInternalBom(bomNSData), options.jsonPretty),
|
|
2171
2337
|
);
|
|
2172
2338
|
}
|
|
2173
2339
|
}
|
|
@@ -2197,7 +2363,7 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2197
2363
|
if (!options.projectType) {
|
|
2198
2364
|
const evidenceLanguage = evinserModule.defaultEvidenceLanguage(
|
|
2199
2365
|
filePath,
|
|
2200
|
-
bomNSData
|
|
2366
|
+
getInternalBom(bomNSData),
|
|
2201
2367
|
options,
|
|
2202
2368
|
);
|
|
2203
2369
|
if (evidenceLanguage) {
|
|
@@ -2209,10 +2375,17 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2209
2375
|
"Skipping the evidence analysis since the BOM lists no package in a language it supports. Pass -t to choose the language.",
|
|
2210
2376
|
);
|
|
2211
2377
|
if (bomNSData) {
|
|
2212
|
-
|
|
2213
|
-
|
|
2378
|
+
// The filter mutates the 1.x model; the rendered 2.0 document is
|
|
2379
|
+
// refreshed below, once, after this last mutation.
|
|
2380
|
+
const filteredBom = applyEvidenceBasedFilter(
|
|
2381
|
+
getInternalBom(bomNSData),
|
|
2214
2382
|
options,
|
|
2215
2383
|
);
|
|
2384
|
+
if (bomNSData.internalBomJson) {
|
|
2385
|
+
bomNSData.internalBomJson = filteredBom;
|
|
2386
|
+
} else {
|
|
2387
|
+
bomNSData.bomJson = filteredBom;
|
|
2388
|
+
}
|
|
2216
2389
|
}
|
|
2217
2390
|
} else {
|
|
2218
2391
|
const evinseOptions = evinserModule.buildEvinseOptions(
|
|
@@ -2220,6 +2393,12 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2220
2393
|
args,
|
|
2221
2394
|
internalCycloneDxInputPath || options.output,
|
|
2222
2395
|
);
|
|
2396
|
+
// The analysis reads the in-memory 1.x model. At 2.0 that model is
|
|
2397
|
+
// labelled 2.0 but is not a 2.0 document, so it is handed over
|
|
2398
|
+
// directly instead of being read back from the temporary file.
|
|
2399
|
+
if (bomNSData?.internalBomJson) {
|
|
2400
|
+
evinseOptions.inputBomJson = bomNSData.internalBomJson;
|
|
2401
|
+
}
|
|
2223
2402
|
try {
|
|
2224
2403
|
const dbObjMap = await evinserModule.prepareDB(evinseOptions);
|
|
2225
2404
|
if (dbObjMap) {
|
|
@@ -2229,16 +2408,31 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2229
2408
|
);
|
|
2230
2409
|
const evinseJson = await evinserModule.createEvinseFile(
|
|
2231
2410
|
sliceArtefacts,
|
|
2232
|
-
evinseOptions,
|
|
2411
|
+
{ ...evinseOptions, returnInternalModel: true },
|
|
2233
2412
|
);
|
|
2234
2413
|
// The scope filter is deferred until here so the analyzers get to
|
|
2235
|
-
// prove that an optional dependency is actually used.
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2414
|
+
// prove that an optional dependency is actually used. At 2.0
|
|
2415
|
+
// createEvinseFile runs postProcess again and would return the
|
|
2416
|
+
// rendered 2.0 document; `returnInternalModel` asks for the 1.x
|
|
2417
|
+
// model instead, which becomes the internal model and is
|
|
2418
|
+
// re-rendered below.
|
|
2419
|
+
const evinseInternalBom = evinseJson;
|
|
2420
|
+
if (bomNSData.internalBomJson) {
|
|
2421
|
+
bomNSData.internalBomJson = applyEvidenceBasedFilter(
|
|
2422
|
+
evinseInternalBom,
|
|
2423
|
+
options,
|
|
2424
|
+
);
|
|
2425
|
+
} else {
|
|
2426
|
+
bomNSData.bomJson = applyEvidenceBasedFilter(
|
|
2427
|
+
evinseInternalBom,
|
|
2428
|
+
options,
|
|
2429
|
+
);
|
|
2430
|
+
}
|
|
2431
|
+
if (options.print && evinseInternalBom) {
|
|
2432
|
+
printOccurrences(evinseInternalBom);
|
|
2433
|
+
printCallStack(evinseInternalBom);
|
|
2240
2434
|
printReachables(sliceArtefacts);
|
|
2241
|
-
printServices(
|
|
2435
|
+
printServices(evinseInternalBom);
|
|
2242
2436
|
}
|
|
2243
2437
|
}
|
|
2244
2438
|
} catch (err) {
|
|
@@ -2253,6 +2447,10 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2253
2447
|
}
|
|
2254
2448
|
}
|
|
2255
2449
|
}
|
|
2450
|
+
// The last post-postProcess mutation is done; at 2.0 the rendered document
|
|
2451
|
+
// is refreshed from the internal model once, before validation, signing
|
|
2452
|
+
// and writing. At 1.x this is a no-op.
|
|
2453
|
+
refreshRenderedBom(bomNSData, options);
|
|
2256
2454
|
// Perform automatic validation
|
|
2257
2455
|
if (options.validate && bomNSData?.bomJson) {
|
|
2258
2456
|
thoughtLog("Wait, let's check the generated BOM file for any issues.");
|
|
@@ -2306,7 +2504,12 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2306
2504
|
target: "spdx",
|
|
2307
2505
|
});
|
|
2308
2506
|
} else {
|
|
2309
|
-
|
|
2507
|
+
// The SPDX converter reads the 1.x shape; at 2.0 that is the internal
|
|
2508
|
+
// model.
|
|
2509
|
+
bomNSData.spdxJson = convertCycloneDxToSpdx(
|
|
2510
|
+
getInternalBom(bomNSData),
|
|
2511
|
+
options,
|
|
2512
|
+
);
|
|
2310
2513
|
recordActivity({
|
|
2311
2514
|
kind: "convert",
|
|
2312
2515
|
status: "completed",
|
|
@@ -2509,6 +2712,20 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2509
2712
|
status: "blocked",
|
|
2510
2713
|
target: options.serverUrl,
|
|
2511
2714
|
});
|
|
2715
|
+
} else if (isCycloneDx20SpecVersion(bomNSData.bomJson?.specVersion)) {
|
|
2716
|
+
// Unreachable from the CLI, which refuses this before generating; kept
|
|
2717
|
+
// so a 2.0 document can never reach Dependency-Track.
|
|
2718
|
+
recordActivity({
|
|
2719
|
+
kind: "submit",
|
|
2720
|
+
reason: DEPENDENCY_TRACK_CDX20_ERROR,
|
|
2721
|
+
status: "blocked",
|
|
2722
|
+
target: options.serverUrl,
|
|
2723
|
+
});
|
|
2724
|
+
console.error(DEPENDENCY_TRACK_CDX20_ERROR);
|
|
2725
|
+
if (cleanup) {
|
|
2726
|
+
cleanupSourceDir(srcDir);
|
|
2727
|
+
}
|
|
2728
|
+
process.exit(1);
|
|
2512
2729
|
} else {
|
|
2513
2730
|
try {
|
|
2514
2731
|
recordActivity({
|
|
@@ -2547,7 +2764,8 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2547
2764
|
try {
|
|
2548
2765
|
const { buildPublishCollectionPayload, publishTeaCollection } =
|
|
2549
2766
|
await import("../lib/ecosystems/tea.js");
|
|
2550
|
-
const parentComponent =
|
|
2767
|
+
const parentComponent =
|
|
2768
|
+
getInternalBom(bomNSData).metadata?.component || {};
|
|
2551
2769
|
const projectName =
|
|
2552
2770
|
options.teaCollectionName ||
|
|
2553
2771
|
parentComponent.name ||
|
|
@@ -2623,17 +2841,18 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2623
2841
|
thoughtLog("BOM file is also available in .proto format!");
|
|
2624
2842
|
}
|
|
2625
2843
|
}
|
|
2626
|
-
if (options.print && bomNSData
|
|
2627
|
-
|
|
2844
|
+
if (options.print && getInternalBom(bomNSData)?.components) {
|
|
2845
|
+
const printBom = getInternalBom(bomNSData);
|
|
2846
|
+
printSummary(printBom);
|
|
2628
2847
|
if (options.includeFormulation) {
|
|
2629
|
-
printFormulation(
|
|
2848
|
+
printFormulation(printBom);
|
|
2630
2849
|
}
|
|
2631
|
-
printDependencyTree(
|
|
2632
|
-
printTable(
|
|
2850
|
+
printDependencyTree(printBom);
|
|
2851
|
+
printTable(printBom);
|
|
2633
2852
|
// CBOM related print
|
|
2634
2853
|
if (options.includeCrypto) {
|
|
2635
|
-
printTable(
|
|
2636
|
-
printDependencyTree(
|
|
2854
|
+
printTable(printBom, ["cryptographic-asset"]);
|
|
2855
|
+
printDependencyTree(printBom, "provides");
|
|
2637
2856
|
}
|
|
2638
2857
|
}
|
|
2639
2858
|
if (isDryRun || DEBUG_MODE) {
|