@cdxgen/cdxgen 13.5.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 +17 -10
- package/bin/audit.js +7 -4
- package/bin/cdxgen.js +260 -37
- package/bin/convert.js +146 -22
- package/bin/evinse.js +28 -3
- package/bin/repl.js +47 -3
- package/bin/sign.js +211 -34
- package/bin/tracebom.js +18 -6
- package/bin/validate.js +24 -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/license-aliases.json +24 -2
- package/data/pqc-migration.json +239 -0
- package/data/remediations.json +176 -0
- package/data/rules/ai-bom.yaml +1 -1
- package/data/rules/brotli-decoder.yaml +107 -0
- package/data/rules/cbom-security.yaml +4 -3
- package/data/rules/package-integrity.yaml +28 -0
- package/data/rules/vscode-extensions.yaml +75 -0
- package/data/spdx-license-list.json +121 -7
- package/data/spdx-licenses.json +69 -0
- package/data/spdx.schema.json +845 -2
- package/lib/audit/index.js +25 -3
- package/lib/cli/bomAssembly.js +172 -4
- package/lib/cli/cliOptions.js +121 -17
- package/lib/cli/index.js +720 -902
- package/lib/cli/jsBom.js +156 -64
- package/lib/cli/jvmBom.js +602 -86
- package/lib/cli/managedBom.js +161 -19
- package/lib/cli/nativeBom.js +52 -5
- package/lib/core/boundedFile.js +344 -0
- package/lib/core/brotliProbe.js +182 -0
- package/lib/core/env.js +34 -0
- package/lib/core/fs.js +138 -3
- package/lib/core/globPatterns.js +218 -0
- package/lib/core/httpClient.js +98 -1
- package/lib/core/lockPaths.js +38 -0
- package/lib/core/paths.js +24 -1
- package/lib/core/processTree.js +100 -8
- package/lib/core/projectConfig.js +332 -25
- package/lib/core/toolRegistry.js +184 -0
- package/lib/ecosystems/cppEvidence.js +263 -106
- package/lib/ecosystems/cppIncludeResolver.js +16 -5
- package/lib/ecosystems/denoutils.js +2 -2
- package/lib/ecosystems/ecosystems.js +25 -10
- package/lib/ecosystems/gemHostProbe.js +301 -0
- package/lib/ecosystems/golem.js +3 -8
- package/lib/ecosystems/gradleutils.js +1909 -229
- 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-bazel.js +107 -6
- package/lib/ecosystems/parsers-js.js +505 -22
- package/lib/ecosystems/parsers-misc.js +209 -20
- package/lib/ecosystems/parsers-python.js +178 -30
- package/lib/ecosystems/parsers-rust.js +117 -15
- package/lib/ecosystems/pythonutils.js +128 -2
- package/lib/ecosystems/remote/huggingface.js +22 -0
- package/lib/ecosystems/rubyutils.js +538 -31
- package/lib/ecosystems/rusi.js +2 -4
- package/lib/ecosystems/scalacliutils.js +2 -0
- package/lib/ecosystems/scalasem.js +798 -152
- package/lib/ecosystems/vendoredCode.js +237 -3
- package/lib/ecosystems/venvProbe.js +360 -0
- package/lib/evinser/evinser.js +536 -71
- package/lib/evinser/scalasem.js +5 -1
- package/lib/helpers/agenticToolutils.js +525 -94
- package/lib/helpers/bomSigner.js +43 -9
- package/lib/helpers/jssSigner.js +1276 -0
- package/lib/helpers/vsixutils.js +1574 -315
- 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/atomUtils.js +77 -0
- package/lib/inventory/bomUtils.js +8 -1
- package/lib/inventory/brotliDecoder.js +142 -0
- package/lib/inventory/buildToolRateLimit.js +1 -1
- package/lib/inventory/cbomutils.js +56 -7
- 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 +141 -13
- package/lib/inventory/dosai.js +375 -6
- package/lib/inventory/dosaiParsers.js +3 -6
- package/lib/inventory/dotnetRuntime.js +367 -0
- package/lib/inventory/ecosystemFormulationParsers.js +979 -0
- package/lib/inventory/envcontext.js +436 -48
- package/lib/inventory/evidenceUtils.js +13 -1
- package/lib/inventory/fetchBatch.js +1 -1
- package/lib/inventory/formulationParsers.js +124 -14
- package/lib/inventory/gtfobins.js +13 -0
- package/lib/inventory/hbom.js +45 -6
- package/lib/inventory/hbomLoader.js +166 -0
- package/lib/inventory/hostRuntimeProbe.js +686 -0
- package/lib/inventory/jvmLocalRepos.js +9 -2
- package/lib/inventory/jvmToolEnv.js +29 -0
- package/lib/inventory/licenseEnhancer.js +12 -0
- package/lib/inventory/mavenCentralMirror.js +534 -0
- package/lib/inventory/mcpConfigParser.js +5 -0
- package/lib/inventory/nodeBuildInfo.js +218 -0
- package/lib/inventory/nodeHostProbe.js +202 -0
- package/lib/inventory/occurrenceKey.js +90 -0
- package/lib/inventory/osPackageResolver.js +182 -0
- package/lib/inventory/phpBuildInfo.js +10 -59
- package/lib/inventory/phpHostProbe.js +32 -488
- package/lib/inventory/pqcMigration.js +426 -0
- package/lib/inventory/rubyBuildInfo.js +972 -0
- package/lib/inventory/rubyHostProbe.js +218 -0
- package/lib/inventory/rustFormulationParser.js +21 -10
- package/lib/inventory/scalaCoords.js +4 -3
- package/lib/inventory/scalaDedupe.js +440 -0
- package/lib/inventory/source.js +114 -8
- package/lib/managers/binary.js +337 -3
- package/lib/managers/docker.js +79 -0
- package/lib/parsers/huggingfaceManifest.js +9 -1
- package/lib/parsers/huggingfaceUtils.js +18 -0
- package/lib/parsers/kiroPermissions.js +166 -0
- package/lib/parsers/largeJson.js +28 -11
- package/lib/parsers/vscodeExtensionId.js +183 -0
- package/lib/server/server.js +48 -35
- package/lib/stages/postgen/postgen.js +41 -1
- package/lib/stages/postgen/ruleEngine.js +13 -5
- package/lib/stages/postgen/specVersionCompat.js +76 -0
- package/lib/stages/pregen/envAudit.js +1 -0
- package/lib/stages/pregen/pregen.js +114 -57
- package/lib/validator/bomValidator.js +14 -2
- package/lib/validator/complianceEngine.js +30 -3
- package/lib/validator/complianceRules.js +1416 -4
- package/lib/validator/generated/validate-1.6.mjs +1 -1
- package/lib/validator/generated/validate-1.7.mjs +1 -1
- package/lib/validator/generated/validate-2.0.mjs +57554 -13851
- package/lib/validator/index.js +49 -8
- package/lib/validator/reporters/json.js +6 -0
- package/package.json +11 -10
- 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 +29 -1
- 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 +3 -18
- 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 +100 -0
- package/types/lib/core/boundedFile.d.ts.map +1 -0
- package/types/lib/core/brotliProbe.d.ts +37 -0
- package/types/lib/core/brotliProbe.d.ts.map +1 -0
- package/types/lib/core/env.d.ts +14 -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/httpClient.d.ts +24 -0
- package/types/lib/core/httpClient.d.ts.map +1 -1
- package/types/lib/core/lockPaths.d.ts +19 -0
- package/types/lib/core/lockPaths.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 +17 -4
- 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 +36 -0
- package/types/lib/core/toolRegistry.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +40 -13
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts +2 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/gemHostProbe.d.ts +28 -0
- package/types/lib/ecosystems/gemHostProbe.d.ts.map +1 -0
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +294 -20
- 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-bazel.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +17 -20
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +19 -0
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +10 -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 +19 -1
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +144 -12
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/ecosystems/scalacliutils.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/ecosystems/vendoredCode.d.ts +26 -0
- package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -1
- package/types/lib/ecosystems/venvProbe.d.ts +40 -0
- package/types/lib/ecosystems/venvProbe.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +120 -13
- 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/atomUtils.d.ts +19 -0
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/bomUtils.d.ts.map +1 -1
- package/types/lib/inventory/brotliDecoder.d.ts +58 -0
- package/types/lib/inventory/brotliDecoder.d.ts.map +1 -0
- package/types/lib/inventory/cbomutils.d.ts +17 -0
- package/types/lib/inventory/cbomutils.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 +36 -1
- 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 +91 -0
- package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -0
- 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 +74 -12
- 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/gtfobins.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/hostRuntimeProbe.d.ts +44 -0
- package/types/lib/inventory/hostRuntimeProbe.d.ts.map +1 -0
- package/types/lib/inventory/jvmLocalRepos.d.ts +5 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -1
- package/types/lib/inventory/jvmToolEnv.d.ts +12 -0
- package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
- package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -1
- package/types/lib/inventory/mavenCentralMirror.d.ts +170 -0
- package/types/lib/inventory/mavenCentralMirror.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/nodeBuildInfo.d.ts +95 -0
- package/types/lib/inventory/nodeBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/nodeHostProbe.d.ts +15 -0
- package/types/lib/inventory/nodeHostProbe.d.ts.map +1 -0
- package/types/lib/inventory/occurrenceKey.d.ts +52 -0
- package/types/lib/inventory/occurrenceKey.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +38 -0
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
- package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -1
- package/types/lib/inventory/phpHostProbe.d.ts.map +1 -1
- package/types/lib/inventory/pqcMigration.d.ts +84 -0
- package/types/lib/inventory/pqcMigration.d.ts.map +1 -0
- package/types/lib/inventory/rubyBuildInfo.d.ts +271 -0
- package/types/lib/inventory/rubyBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/rubyHostProbe.d.ts +47 -0
- package/types/lib/inventory/rubyHostProbe.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 +25 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +12 -0
- package/types/lib/managers/docker.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/largeJson.d.ts +4 -3
- package/types/lib/parsers/largeJson.d.ts.map +1 -1
- 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/stages/pregen/envAudit.d.ts.map +1 -1
- package/types/lib/stages/pregen/pregen.d.ts +12 -8
- package/types/lib/stages/pregen/pregen.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/bin/sign.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import crypto from "node:crypto";
|
|
3
4
|
import fs from "node:fs";
|
|
4
5
|
import process from "node:process";
|
|
5
6
|
|
|
@@ -10,14 +11,23 @@ import {
|
|
|
10
11
|
readEnvironmentVariable,
|
|
11
12
|
retrieveCdxgenVersion,
|
|
12
13
|
safeExistsSync,
|
|
14
|
+
safeWriteSync,
|
|
13
15
|
} from "../lib/ecosystems/utils.js";
|
|
14
16
|
import {
|
|
15
17
|
checkSignatureEntries,
|
|
16
18
|
displayValue,
|
|
17
19
|
signBom,
|
|
18
20
|
} from "../lib/helpers/bomSigner.js";
|
|
21
|
+
import {
|
|
22
|
+
countersignJss,
|
|
23
|
+
removeJssSignatures,
|
|
24
|
+
selectJssAlgorithmForKey,
|
|
25
|
+
signJssBom,
|
|
26
|
+
verifyJss,
|
|
27
|
+
} from "../lib/helpers/jssSigner.js";
|
|
19
28
|
import {
|
|
20
29
|
getNonCycloneDxErrorMessage,
|
|
30
|
+
isCycloneDx20SpecVersion,
|
|
21
31
|
isCycloneDxBom,
|
|
22
32
|
} from "../lib/inventory/bomUtils.js";
|
|
23
33
|
import { parseStrictJson } from "../lib/parsers/strictJson.js";
|
|
@@ -41,16 +51,18 @@ const args = _yargs
|
|
|
41
51
|
})
|
|
42
52
|
.option("algorithm", {
|
|
43
53
|
alias: "a",
|
|
44
|
-
default: readEnvironmentVariable("SBOM_SIGN_ALGORITHM")
|
|
54
|
+
default: readEnvironmentVariable("SBOM_SIGN_ALGORITHM"),
|
|
55
|
+
defaultDescription:
|
|
56
|
+
"SBOM_SIGN_ALGORITHM, else RS512 for JSF (1.x) or derived from the key for JSS (2.0)",
|
|
45
57
|
description:
|
|
46
|
-
"
|
|
58
|
+
"Signature algorithm (e.g., RS512, ES256, Ed25519). It must match the key type. For a CycloneDX 2.0 (JSS) document it defaults to ES256/ES384/ES512 by curve, RS256 for rsa, PS256 for rsa-pss, Ed25519 or Ed448.",
|
|
47
59
|
})
|
|
48
60
|
.option("mode", {
|
|
49
61
|
alias: "m",
|
|
50
62
|
default: readEnvironmentVariable("SBOM_SIGN_MODE") || "replace",
|
|
51
63
|
choices: ["replace", "signers", "chain"],
|
|
52
64
|
description:
|
|
53
|
-
"Signature mode. Use 'signers' for multi-signing, 'chain' for sequential chaining.",
|
|
65
|
+
"Signature mode. Use 'signers' for multi-signing, 'chain' for sequential chaining. At 2.0 (JSS), 'replace' removes every existing JSS signature, 'signers' appends a root signature (X.590 clause 7.1), and 'chain' countersigns the only root signature (X.590 clause 7.2).",
|
|
54
66
|
})
|
|
55
67
|
.option("verify-existing-with", {
|
|
56
68
|
type: "array",
|
|
@@ -149,6 +161,9 @@ if (args.privateKey) {
|
|
|
149
161
|
|
|
150
162
|
function hasAnySignature(bomJson) {
|
|
151
163
|
if (bomJson.signature) return true;
|
|
164
|
+
// CycloneDX 2.0 carries JSS signatures in `signatures` lists.
|
|
165
|
+
if (Array.isArray(bomJson.signatures) && bomJson.signatures.length)
|
|
166
|
+
return true;
|
|
152
167
|
if (
|
|
153
168
|
Array.isArray(bomJson.components) &&
|
|
154
169
|
bomJson.components.some((c) => c.signature)
|
|
@@ -234,6 +249,189 @@ function checkExistingSignatures(bomJson) {
|
|
|
234
249
|
);
|
|
235
250
|
}
|
|
236
251
|
|
|
252
|
+
function signJsfDocument(bomJson) {
|
|
253
|
+
const jsfAlgorithm = args.algorithm || "RS512";
|
|
254
|
+
checkExistingSignatures(bomJson);
|
|
255
|
+
const signedBom = signBom(bomJson, {
|
|
256
|
+
privateKey: privateKeyContent,
|
|
257
|
+
algorithm: jsfAlgorithm,
|
|
258
|
+
embedPublicKey: args.embedPublicKey,
|
|
259
|
+
embedPublicKeyNested: false,
|
|
260
|
+
keyId: args.keyId,
|
|
261
|
+
mode: args.mode,
|
|
262
|
+
signComponents: args.signComponents,
|
|
263
|
+
signServices: args.signServices,
|
|
264
|
+
signAnnotations: args.signAnnotations,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
const outputPath = args.output || args.input;
|
|
268
|
+
safeWriteSync(outputPath, JSON.stringify(signedBom, null, null));
|
|
269
|
+
|
|
270
|
+
console.log(`Successfully signed BOM and saved to '${outputPath}'`);
|
|
271
|
+
console.log(
|
|
272
|
+
`Mode: ${args.mode} | Algorithm: ${jsfAlgorithm}${args.keyId ? ` | KeyId: ${args.keyId}` : ""}`,
|
|
273
|
+
);
|
|
274
|
+
const rootSignature = signedBom.signature;
|
|
275
|
+
const newEntry =
|
|
276
|
+
rootSignature?.signers?.at(-1) ??
|
|
277
|
+
rootSignature?.chain?.at(-1) ??
|
|
278
|
+
rootSignature;
|
|
279
|
+
if (
|
|
280
|
+
args.embedPublicKey &&
|
|
281
|
+
!String(jsfAlgorithm).startsWith("HS") &&
|
|
282
|
+
newEntry?.publicKey === undefined
|
|
283
|
+
) {
|
|
284
|
+
console.warn(
|
|
285
|
+
"Warning: this key type has no JWK form, so the public key was not embedded in the signature.",
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
return signedBom;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// A JSS (X.590) countersignature of the only root entry vouches for that
|
|
292
|
+
// entry and its chain, so every object of the chain must verify (as for a
|
|
293
|
+
// JSF chain). A new root entry covers the same content as the existing ones,
|
|
294
|
+
// so the existing signatures must pass the cdx-verify policy: at least one
|
|
295
|
+
// entry verifies, no entry that names a given key fails, and every
|
|
296
|
+
// countersignature verifies.
|
|
297
|
+
function checkExistingJssSignatures(bomJson) {
|
|
298
|
+
const chain = args.mode === "chain";
|
|
299
|
+
const keys = (args.verifyExistingWith || []).map((keyFile) => {
|
|
300
|
+
if (!safeExistsSync(keyFile)) {
|
|
301
|
+
throw new Error(`Public key file '${keyFile}' not found.`);
|
|
302
|
+
}
|
|
303
|
+
return fs.readFileSync(keyFile, "utf8");
|
|
304
|
+
});
|
|
305
|
+
const verdict = keys.length
|
|
306
|
+
? verifyJss(bomJson, { publicKeys: keys })
|
|
307
|
+
: undefined;
|
|
308
|
+
const results = verdict
|
|
309
|
+
? verdict.results
|
|
310
|
+
: bomJson.signatures.map((entry, index) => ({
|
|
311
|
+
path: `signatures[${index}]`,
|
|
312
|
+
algorithm: entry?.algorithm,
|
|
313
|
+
status: "untrusted",
|
|
314
|
+
reason: "no --verify-existing-with key was given",
|
|
315
|
+
}));
|
|
316
|
+
const unverified = results.filter((result) => result.status !== "verified");
|
|
317
|
+
if (chain ? !unverified.length : verdict?.valid) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const someVerified = unverified.length < results.length;
|
|
321
|
+
const details = unverified.map(
|
|
322
|
+
(result) =>
|
|
323
|
+
` - ${result.path} (${displayValue(result.algorithm)}): ${result.reason || "not verified"}`,
|
|
324
|
+
);
|
|
325
|
+
if (args.allowUnverifiedHistory) {
|
|
326
|
+
console.warn(
|
|
327
|
+
[
|
|
328
|
+
chain
|
|
329
|
+
? `Warning: countersigning a JSS signature chain with ${unverified.length} unverified signature object(s):`
|
|
330
|
+
: someVerified
|
|
331
|
+
? `Warning: appending a JSS signature although ${unverified.length} existing signature object(s) failed verification:`
|
|
332
|
+
: `Warning: appending a JSS signature although none of the ${unverified.length} existing signature object(s) verified:`,
|
|
333
|
+
...details,
|
|
334
|
+
].join("\n"),
|
|
335
|
+
);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
throw new Error(
|
|
339
|
+
[
|
|
340
|
+
chain
|
|
341
|
+
? `the countersignature would vouch for ${unverified.length} existing JSS signature object(s) that could not be verified:`
|
|
342
|
+
: someVerified
|
|
343
|
+
? "the existing JSS signatures do not pass verification, so cdx-verify would reject the signed document:"
|
|
344
|
+
: `none of the ${unverified.length} existing JSS signature object(s) could be verified, so the content may have changed since it was signed:`,
|
|
345
|
+
...details,
|
|
346
|
+
"Pass --verify-existing-with <public key> for each earlier signer, or --allow-unverified-history to sign anyway.",
|
|
347
|
+
].join("\n"),
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Signs a CycloneDX 2.0 document with JSS (ITU-T X.590).
|
|
353
|
+
*
|
|
354
|
+
* - replace: every existing JSS signature is removed (with a warning that
|
|
355
|
+
* names how many), then the root and the nested members are signed;
|
|
356
|
+
* - signers: a root entry is appended. X.590 clause 7.1.2 removes the
|
|
357
|
+
* existing entries before canonicalizing, so they stay valid;
|
|
358
|
+
* - chain: the only root entry is countersigned (X.590 clause 7.2). A JSF
|
|
359
|
+
* chain entry covers every earlier entry, while a JSS countersignature
|
|
360
|
+
* covers only the entry it countersigns, so the two agree only when the
|
|
361
|
+
* root has a single entry; otherwise chain mode is refused.
|
|
362
|
+
*
|
|
363
|
+
* Nested members are signed only when no root signature is kept: signing
|
|
364
|
+
* them changes content the existing root entries cover.
|
|
365
|
+
*/
|
|
366
|
+
function signJssDocument(bomJson) {
|
|
367
|
+
if (args.embedPublicKey === false) {
|
|
368
|
+
throw new Error(
|
|
369
|
+
"--no-embed-public-key is not supported for CycloneDX 2.0 (JSS): X.590 clause 6.2.1 requires public_key, public_cert_chain, cert_url or thumbprint in every signature object, and cdx-sign writes public_key.",
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
if (args.keyId !== undefined) {
|
|
373
|
+
console.warn(
|
|
374
|
+
"Warning: --key-id is not used for CycloneDX 2.0 (JSS) signatures, which identify the key by public_key.",
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
let privateKey;
|
|
378
|
+
try {
|
|
379
|
+
privateKey = crypto.createPrivateKey(privateKeyContent);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
throw new Error(`Unable to load the JSS signing key: ${error.message}`);
|
|
382
|
+
}
|
|
383
|
+
const algorithm = args.algorithm || selectJssAlgorithmForKey(privateKey);
|
|
384
|
+
const rootEntries = Array.isArray(bomJson.signatures)
|
|
385
|
+
? bomJson.signatures
|
|
386
|
+
: [];
|
|
387
|
+
const appending = args.mode !== "replace" && rootEntries.length > 0;
|
|
388
|
+
const nestedFlags = [
|
|
389
|
+
["components", args.signComponents],
|
|
390
|
+
["services", args.signServices],
|
|
391
|
+
["annotations", args.signAnnotations],
|
|
392
|
+
];
|
|
393
|
+
if (appending) {
|
|
394
|
+
const requested = nestedFlags.find(([, value]) => value === true);
|
|
395
|
+
if (requested) {
|
|
396
|
+
throw new Error(
|
|
397
|
+
`Cannot sign ${requested[0]} while appending a ${args.mode} JSS signature, because that changes content covered by the existing root signature(s). Sign the root only (for example, --no-sign-${requested[0]}), or use --mode replace.`,
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
if (args.mode === "chain" && rootEntries.length !== 1) {
|
|
401
|
+
throw new Error(
|
|
402
|
+
`--mode chain is not supported for JSS when the BOM has ${rootEntries.length} root signatures: an X.590 clause 7.2 countersignature covers only the entry it countersigns, while a chain entry must cover every earlier entry. Use --mode signers to append a root signature.`,
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
checkExistingJssSignatures(bomJson);
|
|
406
|
+
}
|
|
407
|
+
// At 2.0 the nested members (inventories, their components, compositions
|
|
408
|
+
// and annotations) are signed together; any --no-sign-* signs the root
|
|
409
|
+
// only.
|
|
410
|
+
const deep = !appending && nestedFlags.every(([, value]) => value !== false);
|
|
411
|
+
const signOptions = { algorithm, privateKey };
|
|
412
|
+
let signedBom;
|
|
413
|
+
let label = args.mode;
|
|
414
|
+
if (args.mode === "replace") {
|
|
415
|
+
const { bom, removed } = removeJssSignatures(bomJson);
|
|
416
|
+
if (removed) {
|
|
417
|
+
console.warn(
|
|
418
|
+
`Replacing ${removed} existing JSS signature(s) (--mode replace). Use --mode signers to keep them.`,
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
signedBom = signJssBom(bom, { ...signOptions, deep });
|
|
422
|
+
} else if (appending && args.mode === "chain") {
|
|
423
|
+
signedBom = countersignJss(bomJson, { ...signOptions, index: 0 });
|
|
424
|
+
label = "chain (X.590 clause 7.2 countersignature)";
|
|
425
|
+
} else {
|
|
426
|
+
signedBom = signJssBom(bomJson, { ...signOptions, deep });
|
|
427
|
+
if (args.mode === "chain") {
|
|
428
|
+
label = "chain (first signature)";
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
console.log(`Mode: ${label} | Format: JSS | Algorithm: ${algorithm}`);
|
|
432
|
+
return signedBom;
|
|
433
|
+
}
|
|
434
|
+
|
|
237
435
|
try {
|
|
238
436
|
const bomJson = parseStrictJson(fs.readFileSync(args.input));
|
|
239
437
|
if (!isCycloneDxBom(bomJson)) {
|
|
@@ -243,39 +441,18 @@ try {
|
|
|
243
441
|
|
|
244
442
|
let signedBom = bomJson;
|
|
245
443
|
if (hasPrivateKey && privateKeyContent) {
|
|
246
|
-
checkExistingSignatures(bomJson);
|
|
247
|
-
signedBom = signBom(bomJson, {
|
|
248
|
-
privateKey: privateKeyContent,
|
|
249
|
-
algorithm: args.algorithm,
|
|
250
|
-
embedPublicKey: args.embedPublicKey,
|
|
251
|
-
embedPublicKeyNested: false,
|
|
252
|
-
keyId: args.keyId,
|
|
253
|
-
mode: args.mode,
|
|
254
|
-
signComponents: args.signComponents,
|
|
255
|
-
signServices: args.signServices,
|
|
256
|
-
signAnnotations: args.signAnnotations,
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
const outputPath = args.output || args.input;
|
|
260
|
-
fs.writeFileSync(outputPath, JSON.stringify(signedBom, null, null));
|
|
261
|
-
|
|
262
|
-
console.log(`Successfully signed BOM and saved to '${outputPath}'`);
|
|
263
|
-
console.log(
|
|
264
|
-
`Mode: ${args.mode} | Algorithm: ${args.algorithm}${args.keyId ? ` | KeyId: ${args.keyId}` : ""}`,
|
|
265
|
-
);
|
|
266
|
-
const rootSignature = signedBom.signature;
|
|
267
|
-
const newEntry =
|
|
268
|
-
rootSignature?.signers?.at(-1) ??
|
|
269
|
-
rootSignature?.chain?.at(-1) ??
|
|
270
|
-
rootSignature;
|
|
271
444
|
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
newEntry?.publicKey === undefined
|
|
445
|
+
isCycloneDx20SpecVersion(bomJson.specVersion) ||
|
|
446
|
+
bomJson.specFormat !== undefined
|
|
275
447
|
) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
);
|
|
448
|
+
// A CycloneDX 2.0 document signs with JSS (ITU-T X.590); the JSF
|
|
449
|
+
// signer below is 1.x only.
|
|
450
|
+
signedBom = signJssDocument(bomJson);
|
|
451
|
+
const jssOutputPath = args.output || args.input;
|
|
452
|
+
safeWriteSync(jssOutputPath, JSON.stringify(signedBom, null, null));
|
|
453
|
+
console.log(`Successfully signed BOM and saved to '${jssOutputPath}'`);
|
|
454
|
+
} else {
|
|
455
|
+
signedBom = signJsfDocument(bomJson);
|
|
279
456
|
}
|
|
280
457
|
} else {
|
|
281
458
|
if (!hasAnySignature(bomJson)) {
|
package/bin/tracebom.js
CHANGED
|
@@ -13,7 +13,12 @@ import {
|
|
|
13
13
|
retrieveCdxgenVersion,
|
|
14
14
|
safeWriteSync,
|
|
15
15
|
} from "../lib/ecosystems/utils.js";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
DEFAULT_CDX_SPEC_VERSION,
|
|
18
|
+
isCycloneDx20SpecVersion,
|
|
19
|
+
} from "../lib/inventory/bomUtils.js";
|
|
20
|
+
import { renderCycloneDx20 } from "../lib/inventory/cyclonedx20.js";
|
|
21
|
+
import { hardwareRenderContext } from "../lib/inventory/hbomLoader.js";
|
|
17
22
|
import { applySpecVersionCompatibility } from "../lib/stages/postgen/specVersionCompat.js";
|
|
18
23
|
|
|
19
24
|
const _yargs = yargs(hideBin(process.argv));
|
|
@@ -339,10 +344,20 @@ const options = {
|
|
|
339
344
|
process.exit(1);
|
|
340
345
|
}
|
|
341
346
|
// tracebom skips postProcess, so the downgrade to an older --spec-version
|
|
342
|
-
// (for example dropping the 1.7 algorithmFamily of traced crypto) runs here
|
|
347
|
+
// (for example dropping the 1.7 algorithmFamily of traced crypto) runs here,
|
|
348
|
+
// and a 2.0 target renders the document with the postgen renderer.
|
|
343
349
|
applySpecVersionCompatibility(bomJson, options);
|
|
350
|
+
const serviceCount = bomJson?.services?.length || 0;
|
|
351
|
+
const componentCount = bomJson?.components?.length || 0;
|
|
352
|
+
const outputBomJson = isCycloneDx20SpecVersion(options.specVersion)
|
|
353
|
+
? renderCycloneDx20(bomJson, await hardwareRenderContext(bomJson))
|
|
354
|
+
: bomJson;
|
|
344
355
|
|
|
345
|
-
const jsonPayload = JSON.stringify(
|
|
356
|
+
const jsonPayload = JSON.stringify(
|
|
357
|
+
outputBomJson,
|
|
358
|
+
null,
|
|
359
|
+
DEBUG_MODE ? 2 : null,
|
|
360
|
+
);
|
|
346
361
|
|
|
347
362
|
if (args.print) {
|
|
348
363
|
// The document is the payload, so it bypasses the console shim.
|
|
@@ -350,9 +365,6 @@ const options = {
|
|
|
350
365
|
}
|
|
351
366
|
|
|
352
367
|
safeWriteSync(options.output, jsonPayload);
|
|
353
|
-
|
|
354
|
-
const serviceCount = bomJson?.services?.length || 0;
|
|
355
|
-
const componentCount = bomJson?.components?.length || 0;
|
|
356
368
|
const summaryParts = [
|
|
357
369
|
`SBOM written to ${options.output}`,
|
|
358
370
|
`${componentCount} component(s)`,
|
package/bin/validate.js
CHANGED
|
@@ -19,6 +19,8 @@ import process from "node:process";
|
|
|
19
19
|
import yargs from "yargs";
|
|
20
20
|
import { hideBin } from "yargs/helpers";
|
|
21
21
|
|
|
22
|
+
import { thoughtLog } from "../lib/core/logger.js";
|
|
23
|
+
import { installConsoleShim, restoreConsole } from "../lib/core/ui.js";
|
|
22
24
|
import {
|
|
23
25
|
dirNameStr,
|
|
24
26
|
retrieveCdxgenVersion,
|
|
@@ -31,6 +33,7 @@ import {
|
|
|
31
33
|
getNonCycloneDxErrorMessage,
|
|
32
34
|
isCycloneDxBom,
|
|
33
35
|
} from "../lib/inventory/bomUtils.js";
|
|
36
|
+
import { formatReadLossNotice } from "../lib/inventory/cyclonedx20.js";
|
|
34
37
|
import {
|
|
35
38
|
importProtobomModule,
|
|
36
39
|
isProtoBomPath,
|
|
@@ -79,12 +82,12 @@ const args = _yargs
|
|
|
79
82
|
alias: "b",
|
|
80
83
|
type: "string",
|
|
81
84
|
description:
|
|
82
|
-
"Comma-separated list of compliance benchmark aliases to include in the scorecards (scvs, scvs-l1, scvs-l2, scvs-l3, cra). Defaults to all.",
|
|
85
|
+
"Comma-separated list of compliance benchmark aliases to include in the scorecards (scvs, scvs-l1, scvs-l2, scvs-l3, cra, cisa, cisa-ai). Defaults to all.",
|
|
83
86
|
})
|
|
84
87
|
.option("categories", {
|
|
85
88
|
type: "string",
|
|
86
89
|
description:
|
|
87
|
-
"Comma-separated list of compliance rule categories to evaluate (compliance-scvs, compliance-cra). Defaults to all.",
|
|
90
|
+
"Comma-separated list of compliance rule categories to evaluate (compliance-scvs, compliance-cra, compliance-cisa, compliance-cisa-ai). Defaults to all.",
|
|
88
91
|
})
|
|
89
92
|
.option("min-severity", {
|
|
90
93
|
type: "string",
|
|
@@ -144,6 +147,11 @@ const args = _yargs
|
|
|
144
147
|
.help()
|
|
145
148
|
.wrap(Math.min(120, yargs().terminalWidth())).argv;
|
|
146
149
|
|
|
150
|
+
// stdout carries the report and nothing else; messages from the validators
|
|
151
|
+
// go to the diagnostic stream so `-r json` and `-r sarif` stay parseable.
|
|
152
|
+
installConsoleShim();
|
|
153
|
+
process.once("exit", restoreConsole);
|
|
154
|
+
|
|
147
155
|
/**
|
|
148
156
|
* Loads the BOM. When signatures are verified, the text must also pass
|
|
149
157
|
* parseStrictJson(), and `strictError` explains why it did not.
|
|
@@ -317,7 +325,20 @@ try {
|
|
|
317
325
|
writeOrPrint(output, args.reportFile);
|
|
318
326
|
|
|
319
327
|
for (const e of report.validationErrors || []) {
|
|
320
|
-
console.error(
|
|
328
|
+
console.error(
|
|
329
|
+
e.stage === "read"
|
|
330
|
+
? `cdx-validate: ${e.message}`
|
|
331
|
+
: `cdx-validate: ${e.stage} validation threw: ${e.message}`,
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
// The deep checks and compliance rules read the 1.x-shaped model of a 2.0
|
|
335
|
+
// input; the losses name the parts of the input they never saw. stderr,
|
|
336
|
+
// because stdout may carry the json or sarif report.
|
|
337
|
+
if (report.readLosses?.length) {
|
|
338
|
+
console.error(formatReadLossNotice(report.readLosses));
|
|
339
|
+
for (const loss of report.readLosses) {
|
|
340
|
+
thoughtLog(`cdx-validate 2.0 loss at ${loss.pointer}: ${loss.reason}`);
|
|
341
|
+
}
|
|
321
342
|
}
|
|
322
343
|
|
|
323
344
|
const { shouldFail: fail, reason } = shouldFail(report, {
|
package/bin/verify.js
CHANGED
|
@@ -19,8 +19,10 @@ import {
|
|
|
19
19
|
loadVerificationKey,
|
|
20
20
|
verifyBomSignatures,
|
|
21
21
|
} from "../lib/helpers/bomSigner.js";
|
|
22
|
+
import { verifyJssBom } from "../lib/helpers/jssSigner.js";
|
|
22
23
|
import {
|
|
23
24
|
getNonCycloneDxErrorMessage,
|
|
25
|
+
isCycloneDx20SpecVersion,
|
|
24
26
|
isCycloneDxBom,
|
|
25
27
|
} from "../lib/inventory/bomUtils.js";
|
|
26
28
|
import { isProtoBomPath } from "../lib/inventory/protobomLoader.js";
|
|
@@ -45,30 +47,30 @@ const args = _yargs
|
|
|
45
47
|
type: "array",
|
|
46
48
|
string: true,
|
|
47
49
|
description:
|
|
48
|
-
"Trusted public key in PEM format. Repeat to trust several keys; a signature entry verifies when one of them verifies it.",
|
|
50
|
+
"Trusted public key in PEM format. Repeat to trust several keys; a signature entry verifies when one of them verifies it. CycloneDX 2.0 (JSS) documents need at least one: the public_key embedded in a JSS entry is never trusted on its own, and an entry whose public_key is one of these keys must verify with it.",
|
|
49
51
|
})
|
|
50
52
|
.option("secret-key", {
|
|
51
53
|
type: "string",
|
|
52
54
|
description:
|
|
53
|
-
"File holding the shared secret for HMAC (HS256, HS384, HS512) signatures. HMAC signatures are only accepted with this option.",
|
|
55
|
+
"File holding the shared secret for HMAC (HS256, HS384, HS512) signatures. HMAC signatures are only accepted with this option. Not supported for CycloneDX 2.0 (JSS) documents.",
|
|
54
56
|
})
|
|
55
57
|
.option("deep", {
|
|
56
58
|
type: "boolean",
|
|
57
59
|
default: true,
|
|
58
60
|
description:
|
|
59
|
-
"Strictly verify all nested component, service, and annotation signatures against the provided keys. Pass --no-deep to verify only the root signature.",
|
|
61
|
+
"Strictly verify all nested component, service, and annotation signatures against the provided keys (at 2.0: inventories, their components, compositions, and annotations). Pass --no-deep to verify only the root signature.",
|
|
60
62
|
})
|
|
61
63
|
.option("require-all", {
|
|
62
64
|
type: "boolean",
|
|
63
65
|
default: false,
|
|
64
66
|
description:
|
|
65
|
-
"Require every entry of a signers or chain signature to verify with one of the keys, instead of at least one.",
|
|
67
|
+
"Require every entry of a signers or chain signature to verify with one of the keys, instead of at least one. At 2.0 every JSS signature object, countersignatures included, must verify with one of the keys, and every key must verify a root signature object.",
|
|
66
68
|
})
|
|
67
69
|
.option("allow-nested-only", {
|
|
68
70
|
type: "boolean",
|
|
69
71
|
default: false,
|
|
70
72
|
description:
|
|
71
|
-
"Accept a BOM without a root signature when every component, service, and annotation carries a signature that verifies. No signature then covers the other members of the BOM.",
|
|
73
|
+
"Accept a BOM without a root signature when every component, service, and annotation carries a signature that verifies (at 2.0: every inventory, inventory component, composition, and annotation). No signature then covers the other members of the BOM.",
|
|
72
74
|
})
|
|
73
75
|
.completion("completion", "Generate bash/zsh completion")
|
|
74
76
|
.epilogue("for documentation, visit https://cdxgen.github.io/cdxgen")
|
|
@@ -159,6 +161,16 @@ if (!isCycloneDxBom(bomJson)) {
|
|
|
159
161
|
console.log(getNonCycloneDxErrorMessage(bomJson, "cdx-verify"));
|
|
160
162
|
process.exit(1);
|
|
161
163
|
}
|
|
164
|
+
// A CycloneDX 2.0 document carries JSS signatures (ITU-T X.590).
|
|
165
|
+
const isJssBom =
|
|
166
|
+
isCycloneDx20SpecVersion(bomJson.specVersion) ||
|
|
167
|
+
bomJson.specFormat !== undefined;
|
|
168
|
+
if (isJssBom && args.secretKey) {
|
|
169
|
+
console.log(
|
|
170
|
+
"--secret-key is not supported for CycloneDX 2.0 (JSS) signatures: X.590 clause 6.2.2 says HMAC algorithms SHOULD NOT be used, and cdx-verify does not verify them. Pass the signer's --public-key instead.",
|
|
171
|
+
);
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
162
174
|
|
|
163
175
|
const verificationKeys = [];
|
|
164
176
|
for (const keyFile of args.secretKey ? [args.secretKey] : publicKeyFiles) {
|
|
@@ -205,6 +217,102 @@ function printRejections(node) {
|
|
|
205
217
|
}
|
|
206
218
|
}
|
|
207
219
|
|
|
220
|
+
function describeJssResult(result) {
|
|
221
|
+
const role = result.depth > 0 ? "countersignature" : "signature";
|
|
222
|
+
return `${result.path} ${role} (${displayValue(result.algorithm)})`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function printJssResults(results, prefix = "") {
|
|
226
|
+
for (const result of results) {
|
|
227
|
+
if (result.status === "verified") {
|
|
228
|
+
console.log(
|
|
229
|
+
` ✓ ${prefix}${describeJssResult(result)} verified with key #${result.keyIndex + 1}: ${publicKeyFiles[result.keyIndex]}`,
|
|
230
|
+
);
|
|
231
|
+
} else {
|
|
232
|
+
console.log(
|
|
233
|
+
` - ${prefix}${describeJssResult(result)} ${result.status}: ${result.reason || "not verified"}`,
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (isJssBom) {
|
|
240
|
+
// JSS verification (X.590 clause 8.1, countersignatures clause 7.2) with
|
|
241
|
+
// the trusted --public-key values only (clause 8.1.3 "fetch it from a
|
|
242
|
+
// trusted source"); the same --deep, --require-all and
|
|
243
|
+
// --allow-nested-only policy as the JSF path below.
|
|
244
|
+
let jssReport;
|
|
245
|
+
try {
|
|
246
|
+
jssReport = verifyJssBom(bomJson, {
|
|
247
|
+
publicKeys: verificationKeys,
|
|
248
|
+
deep: args.deep,
|
|
249
|
+
requireAll: args.requireAll,
|
|
250
|
+
allowNestedOnly: args.allowNestedOnly,
|
|
251
|
+
});
|
|
252
|
+
} catch (error) {
|
|
253
|
+
console.log(`JSS verification failed: ${error.message}`);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
for (const error of jssReport.errors) {
|
|
257
|
+
console.log(error);
|
|
258
|
+
}
|
|
259
|
+
if (args.requireAll && jssReport.root) {
|
|
260
|
+
jssReport.root.keysMatched.forEach((matched, index) => {
|
|
261
|
+
if (!matched) {
|
|
262
|
+
console.log(` - key #${index + 1}: ${publicKeyFiles[index]}`);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (jssReport.root) {
|
|
267
|
+
console.log(
|
|
268
|
+
jssReport.root.valid
|
|
269
|
+
? "BOM JSS signatures:"
|
|
270
|
+
: "BOM signature is invalid!",
|
|
271
|
+
);
|
|
272
|
+
for (const reason of jssReport.root.reasons) {
|
|
273
|
+
console.log(` - ${reason}`);
|
|
274
|
+
}
|
|
275
|
+
printJssResults(jssReport.root.results);
|
|
276
|
+
} else if (!args.allowNestedOnly) {
|
|
277
|
+
console.log(
|
|
278
|
+
"Pass --allow-nested-only to accept a BOM whose inventories, components, compositions, and annotations are all signed.",
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
const invalidNested = jssReport.nested.filter((item) => !item.valid);
|
|
282
|
+
for (const item of invalidNested) {
|
|
283
|
+
console.log(`${item.path} signature is invalid!`);
|
|
284
|
+
for (const reason of item.reasons) {
|
|
285
|
+
console.log(` - ${reason}`);
|
|
286
|
+
}
|
|
287
|
+
printJssResults(item.results);
|
|
288
|
+
}
|
|
289
|
+
if (invalidNested.length) {
|
|
290
|
+
console.log("One or more nested signatures are invalid!");
|
|
291
|
+
if (jssReport.root?.valid) {
|
|
292
|
+
console.log(
|
|
293
|
+
"The root signature verifies with this key. Nested signatures belong to the party that created them, so pass --no-deep to verify only the root signature with this key.",
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (!jssReport.valid) {
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
const unverified = [
|
|
301
|
+
...jssReport.results,
|
|
302
|
+
...jssReport.nested.flatMap((item) => item.results),
|
|
303
|
+
].filter((result) => result.status !== "verified");
|
|
304
|
+
if (unverified.length) {
|
|
305
|
+
console.log(
|
|
306
|
+
`Warning: ${unverified.length} JSS signature object(s) did not verify with the given key(s). Pass --require-all to fail in that case.`,
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
if (!jssReport.root) {
|
|
310
|
+
console.log(`✓ ${jssReport.nested.length} nested signature(s) are valid!`);
|
|
311
|
+
}
|
|
312
|
+
console.log("JSS signature(s) verified successfully.");
|
|
313
|
+
process.exit(0);
|
|
314
|
+
}
|
|
315
|
+
|
|
208
316
|
const report = verifyBomSignatures(bomJson, verificationKeys, {
|
|
209
317
|
deep: args.deep,
|
|
210
318
|
allowNestedOnly: args.allowNestedOnly,
|