@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
|
@@ -6,6 +6,7 @@ import { build } from "@cdxgen/cdx-purl";
|
|
|
6
6
|
import { safeExistsSync } from "../core/fs.js";
|
|
7
7
|
import { thoughtLog } from "../core/logger.js";
|
|
8
8
|
import { sanitizeBomUrl } from "../core/propertySanitizer.js";
|
|
9
|
+
import { vscodeExtensionPlatformFromPath } from "../parsers/vscodeExtensionId.js";
|
|
9
10
|
import { isAgentSkillSpecValid } from "./agentSkillSpec.js";
|
|
10
11
|
import {
|
|
11
12
|
addDosaiReachabilityProperties,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
} from "./dosaiParsers.js";
|
|
23
24
|
import { createGtfoBinsPropertiesFromRow } from "./gtfobins.js";
|
|
24
25
|
import { createLolbasProperties } from "./lolbas.js";
|
|
26
|
+
import { occurrenceLocationKey } from "./occurrenceKey.js";
|
|
25
27
|
import { isOsPackagePurlType } from "./osPackagePurl.js";
|
|
26
28
|
import {
|
|
27
29
|
createOsQueryFallbackBomRef,
|
|
@@ -369,7 +371,7 @@ export function addEvidenceForDotnet(pkgList, slicesFile, options = {}) {
|
|
|
369
371
|
addDosaiSetValue(
|
|
370
372
|
purlLocationMap,
|
|
371
373
|
modPurl,
|
|
372
|
-
|
|
374
|
+
occurrenceLocationKey(adep.Path, adep.LineNumber),
|
|
373
375
|
);
|
|
374
376
|
}
|
|
375
377
|
}
|
|
@@ -619,6 +621,13 @@ export function convertOSQueryResults(
|
|
|
619
621
|
// The profile an add-on was found in is not part of its purl, so the
|
|
620
622
|
// add-on ID is what tells apart two add-ons that share a name.
|
|
621
623
|
qualifiers = { tag_id: firefoxAddonTagId(res.identifier) };
|
|
624
|
+
} else if (queryObj.purlType === "vscode-extension") {
|
|
625
|
+
// A platform-specific build is a different artefact from the one for
|
|
626
|
+
// another platform, and the extension scan names it the same way.
|
|
627
|
+
const targetPlatform = vscodeExtensionPlatformFromPath(res.path);
|
|
628
|
+
if (targetPlatform) {
|
|
629
|
+
qualifiers = { platform: targetPlatform };
|
|
630
|
+
}
|
|
622
631
|
}
|
|
623
632
|
if (name) {
|
|
624
633
|
name = sanitizeOsQueryIdentity(name);
|
|
@@ -788,11 +797,14 @@ export function convertOSQueryResults(
|
|
|
788
797
|
// profile. Where it was found is not part of what it is, so the path is an
|
|
789
798
|
// occurrence rather than a subpath: a home directory stays out of the purl, and
|
|
790
799
|
// one package installed in two places is one component with two occurrences.
|
|
800
|
+
// Chocolatey rows carry the absolute path of the package's .nuspec, which a
|
|
801
|
+
// purl subpath cannot hold, so it is kept as an occurrence like these.
|
|
791
802
|
const LOCATED_PACKAGE_PURL_TYPES = new Set([
|
|
792
803
|
"npm",
|
|
793
804
|
"pypi",
|
|
794
805
|
"chrome-extension",
|
|
795
806
|
"vscode-extension",
|
|
807
|
+
"chocolatey",
|
|
796
808
|
]);
|
|
797
809
|
const LOCATED_PACKAGE_CATEGORIES = new Set(["firefox_addons"]);
|
|
798
810
|
|
|
@@ -221,7 +221,7 @@ export function openHostCircuit(
|
|
|
221
221
|
);
|
|
222
222
|
} else if (breaker === "maven-central") {
|
|
223
223
|
console.warn(
|
|
224
|
-
`${host} ${what}, so cdxgen will not contact it for the next ${minutes} minute(s) and Maven metadata comes from local caches only. Set
|
|
224
|
+
`${host} ${what}, so cdxgen will not contact it for the next ${minutes} minute(s) and Maven metadata comes from local caches only. Set MAVEN_CENTRAL_MIRROR=true to use Google's Maven Central mirror, or name a repository manager in MAVEN_CENTRAL_URL, to keep license enrichment working.`,
|
|
225
225
|
);
|
|
226
226
|
} else {
|
|
227
227
|
console.warn(
|
|
@@ -4,7 +4,9 @@ import { basename } from "node:path";
|
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
|
|
6
6
|
import { readEnvironmentVariable } from "../core/activity.js";
|
|
7
|
+
import { PROJECT_TYPE_ALIASES } from "../core/env.js";
|
|
7
8
|
import { getAllFiles } from "../core/fs.js";
|
|
9
|
+
import { thoughtLog } from "../core/logger.js";
|
|
8
10
|
import { collectOSCryptoLibs } from "./cbomutils.js";
|
|
9
11
|
import { azurePipelinesParser } from "./ciParsers/azurePipelines.js";
|
|
10
12
|
import { circleCiParser } from "./ciParsers/circleCi.js";
|
|
@@ -12,6 +14,13 @@ import { githubActionsParser } from "./ciParsers/githubActions.js";
|
|
|
12
14
|
import { gitlabCiParser } from "./ciParsers/gitlabCi.js";
|
|
13
15
|
import { jenkinsParser } from "./ciParsers/jenkins.js";
|
|
14
16
|
import { trimComponents } from "./depsUtils.js";
|
|
17
|
+
import {
|
|
18
|
+
dotnetProjectFormulationParser,
|
|
19
|
+
formulationSourcePath,
|
|
20
|
+
goModuleFormulationParser,
|
|
21
|
+
makefileFormulationParser,
|
|
22
|
+
pythonRequirementsFormulationParser,
|
|
23
|
+
} from "./ecosystemFormulationParsers.js";
|
|
15
24
|
import {
|
|
16
25
|
collectEnvInfo,
|
|
17
26
|
getBranch,
|
|
@@ -47,8 +56,9 @@ function buildReadmeSecurityComponents(discoveryPath, options) {
|
|
|
47
56
|
if (!scan.hasHiddenUnicode) {
|
|
48
57
|
continue;
|
|
49
58
|
}
|
|
59
|
+
const sourcePath = formulationSourcePath(filePath, discoveryPath);
|
|
50
60
|
const properties = [
|
|
51
|
-
{ name: "internal:SrcFile", value:
|
|
61
|
+
{ name: "internal:SrcFile", value: sourcePath },
|
|
52
62
|
{ name: "cdx:file:kind", value: "readme" },
|
|
53
63
|
{ name: "cdx:file:hasHiddenUnicode", value: "true" },
|
|
54
64
|
{
|
|
@@ -71,7 +81,7 @@ function buildReadmeSecurityComponents(discoveryPath, options) {
|
|
|
71
81
|
});
|
|
72
82
|
}
|
|
73
83
|
components.push({
|
|
74
|
-
"bom-ref": `file:${
|
|
84
|
+
"bom-ref": `file:${sourcePath}`,
|
|
75
85
|
name: basename(filePath),
|
|
76
86
|
properties,
|
|
77
87
|
type: "file",
|
|
@@ -90,13 +100,22 @@ function buildReadmeSecurityComponents(discoveryPath, options) {
|
|
|
90
100
|
* {
|
|
91
101
|
* id: string, // unique stable identifier
|
|
92
102
|
* patterns: string[], // non-empty array of glob patterns for file discovery
|
|
93
|
-
* parse(files: string[], options: Object
|
|
103
|
+
* parse(files: string[], options: Object, context: { rootDir: string }):
|
|
104
|
+
* // synchronous function
|
|
94
105
|
* { workflows?, components?, services?, properties?, dependencies? }
|
|
95
106
|
* }
|
|
96
107
|
* ```
|
|
108
|
+
*
|
|
109
|
+
* `context.rootDir` is the scanned project root. A parser that records file
|
|
110
|
+
* paths records them relative to it, so no path of the scanning machine
|
|
111
|
+
* reaches the BOM.
|
|
97
112
|
*/
|
|
98
113
|
const _parsers = [
|
|
99
114
|
rustFormulationParser,
|
|
115
|
+
makefileFormulationParser,
|
|
116
|
+
goModuleFormulationParser,
|
|
117
|
+
pythonRequirementsFormulationParser,
|
|
118
|
+
dotnetProjectFormulationParser,
|
|
100
119
|
githubActionsParser,
|
|
101
120
|
gitlabCiParser,
|
|
102
121
|
jenkinsParser,
|
|
@@ -187,6 +206,59 @@ const ENV_BLOCKLIST = [
|
|
|
187
206
|
"webhook",
|
|
188
207
|
];
|
|
189
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Remove the parts of every URL in an environment value that can carry
|
|
211
|
+
* credentials: the userinfo before `@`, the query string and the fragment.
|
|
212
|
+
* The value is scanned with indexOf, one URL at a time, so the work stays
|
|
213
|
+
* linear in its length.
|
|
214
|
+
*
|
|
215
|
+
* @param {string} value environment variable value
|
|
216
|
+
* @returns {string} the value with URL credentials, queries and fragments removed
|
|
217
|
+
*/
|
|
218
|
+
function stripUrlCredentials(value) {
|
|
219
|
+
const delimiters = " \t\r\n\"'`,;<>|";
|
|
220
|
+
let result = "";
|
|
221
|
+
let cursor = 0;
|
|
222
|
+
let schemeEnd = value.indexOf("://");
|
|
223
|
+
while (schemeEnd !== -1) {
|
|
224
|
+
const start = schemeEnd + 3;
|
|
225
|
+
let end = start;
|
|
226
|
+
while (end < value.length && !delimiters.includes(value[end])) {
|
|
227
|
+
end += 1;
|
|
228
|
+
}
|
|
229
|
+
const url = value.slice(start, end);
|
|
230
|
+
let authorityEnd = url.length;
|
|
231
|
+
for (const marker of ["/", "?", "#"]) {
|
|
232
|
+
const at = url.indexOf(marker);
|
|
233
|
+
if (at !== -1 && at < authorityEnd) {
|
|
234
|
+
authorityEnd = at;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const authority = url.slice(0, authorityEnd);
|
|
238
|
+
let rest = url.slice(authorityEnd);
|
|
239
|
+
for (const marker of ["?", "#"]) {
|
|
240
|
+
const at = rest.indexOf(marker);
|
|
241
|
+
if (at !== -1) {
|
|
242
|
+
rest = rest.slice(0, at);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
result += `${value.slice(cursor, start)}${authority.slice(authority.lastIndexOf("@") + 1)}${rest}`;
|
|
246
|
+
cursor = end;
|
|
247
|
+
schemeEnd = value.indexOf("://", end);
|
|
248
|
+
}
|
|
249
|
+
return result + value.slice(cursor);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// The project types a scan asked for, as given on the command line.
|
|
253
|
+
function requestedProjectTypes(options) {
|
|
254
|
+
return [].concat(options?.projectType || []).flatMap((type) =>
|
|
255
|
+
`${type}`
|
|
256
|
+
.split(",")
|
|
257
|
+
.map((part) => part.trim().toLowerCase())
|
|
258
|
+
.filter(Boolean),
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
190
262
|
/**
|
|
191
263
|
* Build the formulation section for a CycloneDX BOM.
|
|
192
264
|
*
|
|
@@ -285,15 +357,45 @@ export function addFormulationSection(filePath, options, context = {}) {
|
|
|
285
357
|
}
|
|
286
358
|
}
|
|
287
359
|
|
|
360
|
+
// The toolchains and OS crypto libraries are probed on the machine cdxgen
|
|
361
|
+
// runs on. A container image or root filesystem was built elsewhere, so the
|
|
362
|
+
// scanning host's tools say nothing about it.
|
|
363
|
+
// Only an explicit container type counts: hasAnyProjectType treats
|
|
364
|
+
// `universal` as every type, and a universal source scan runs on the host.
|
|
365
|
+
const requestedTypes = requestedProjectTypes(options);
|
|
366
|
+
const describesScanningHost = !requestedTypes.some((type) =>
|
|
367
|
+
PROJECT_TYPE_ALIASES.oci.includes(type),
|
|
368
|
+
);
|
|
369
|
+
// An OS inventory (obom) describes the live host. Its path is usually the
|
|
370
|
+
// working directory, such as a home directory or /, so the build-input,
|
|
371
|
+
// CI and README discovery below would walk a tree that is not a project.
|
|
372
|
+
const describesLiveHost =
|
|
373
|
+
requestedTypes.length > 0 &&
|
|
374
|
+
requestedTypes.every((type) => PROJECT_TYPE_ALIASES.os.includes(type));
|
|
375
|
+
if (!describesScanningHost) {
|
|
376
|
+
thoughtLog(
|
|
377
|
+
"Skipping the toolchain and OS crypto library probes for formulation, since they would describe the scanning host and not the image.",
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
288
381
|
// Build environment details (Java, .NET, Python, Node, GCC, Rust, Go, Ruby,
|
|
289
|
-
// PHP, Composer)
|
|
290
|
-
const infoComponents =
|
|
382
|
+
// RubyGems, Bundler, PHP, Composer)
|
|
383
|
+
const infoComponents = describesScanningHost
|
|
384
|
+
? collectEnvInfo(projectPath, options)
|
|
385
|
+
: [];
|
|
291
386
|
if (infoComponents?.length) {
|
|
292
387
|
components = components.concat(infoComponents);
|
|
293
388
|
}
|
|
294
389
|
|
|
295
|
-
// OS crypto libraries (cbom mode)
|
|
296
|
-
|
|
390
|
+
// OS crypto libraries (cbom mode). The queries also read the host's
|
|
391
|
+
// certificates, authorized keys and keychain items, so they run only when
|
|
392
|
+
// formulation was requested explicitly, not when CI, a profile, an OS type
|
|
393
|
+
// or the cbom command turned it on.
|
|
394
|
+
if (
|
|
395
|
+
options.includeCrypto &&
|
|
396
|
+
describesScanningHost &&
|
|
397
|
+
!options.formulationAutomatic
|
|
398
|
+
) {
|
|
297
399
|
const cryptoLibs = collectOSCryptoLibs(options, context?.executeOsQuery);
|
|
298
400
|
if (cryptoLibs?.length) {
|
|
299
401
|
components = components.concat(cryptoLibs);
|
|
@@ -307,8 +409,13 @@ export function addFormulationSection(filePath, options, context = {}) {
|
|
|
307
409
|
const ciProperties = [];
|
|
308
410
|
|
|
309
411
|
const discoveryPath = projectPath || ".";
|
|
412
|
+
if (describesLiveHost) {
|
|
413
|
+
thoughtLog(
|
|
414
|
+
"Skipping build-input, CI and README discovery for formulation, since an OS inventory describes the host and not a project tree.",
|
|
415
|
+
);
|
|
416
|
+
}
|
|
310
417
|
|
|
311
|
-
for (const parser of _parsers) {
|
|
418
|
+
for (const parser of describesLiveHost ? [] : _parsers) {
|
|
312
419
|
const matchedFiles = [];
|
|
313
420
|
for (const pattern of parser.patterns) {
|
|
314
421
|
const found = getAllFiles(discoveryPath, pattern, options);
|
|
@@ -323,7 +430,9 @@ export function addFormulationSection(filePath, options, context = {}) {
|
|
|
323
430
|
|
|
324
431
|
let result;
|
|
325
432
|
try {
|
|
326
|
-
result = parser.parse(uniqueMatchedFiles, options
|
|
433
|
+
result = parser.parse(uniqueMatchedFiles, options, {
|
|
434
|
+
rootDir: discoveryPath,
|
|
435
|
+
});
|
|
327
436
|
} catch (err) {
|
|
328
437
|
// A broken parser must not kill SBOM generation
|
|
329
438
|
console.warn(
|
|
@@ -355,10 +464,9 @@ export function addFormulationSection(filePath, options, context = {}) {
|
|
|
355
464
|
components = components.concat(ciComponents);
|
|
356
465
|
}
|
|
357
466
|
|
|
358
|
-
const readmeSecurityComponents =
|
|
359
|
-
|
|
360
|
-
options
|
|
361
|
-
);
|
|
467
|
+
const readmeSecurityComponents = describesLiveHost
|
|
468
|
+
? []
|
|
469
|
+
: buildReadmeSecurityComponents(discoveryPath, options);
|
|
362
470
|
if (readmeSecurityComponents.length) {
|
|
363
471
|
components = components.concat(readmeSecurityComponents);
|
|
364
472
|
}
|
|
@@ -377,7 +485,9 @@ export function addFormulationSection(filePath, options, context = {}) {
|
|
|
377
485
|
!ENV_BLOCKLIST.some((b) => value.toLowerCase().includes(b)) &&
|
|
378
486
|
value.length
|
|
379
487
|
) {
|
|
380
|
-
|
|
488
|
+
// A registry or mirror URL can carry a password before `@` or a
|
|
489
|
+
// token in its query string, so only the scheme, host and path stay.
|
|
490
|
+
environmentVars.push({ name: aevar, value: stripUrlCredentials(value) });
|
|
381
491
|
}
|
|
382
492
|
}
|
|
383
493
|
|
|
@@ -17,6 +17,15 @@ const MATCH_FIELDS = [
|
|
|
17
17
|
"executable",
|
|
18
18
|
"description",
|
|
19
19
|
];
|
|
20
|
+
// Rows of these categories name an account, not a program: a user called
|
|
21
|
+
// `node` or `git` is no use of the binary of that name, and the GECOS comment
|
|
22
|
+
// in the description is free text about the account.
|
|
23
|
+
const ACCOUNT_CATEGORIES = new Set([
|
|
24
|
+
"authorized_keys_snapshot",
|
|
25
|
+
"logged_in_users_snapshot",
|
|
26
|
+
"users_snapshot",
|
|
27
|
+
]);
|
|
28
|
+
const ACCOUNT_SKIPPED_FIELDS = new Set(["name", "description"]);
|
|
20
29
|
const UNIX_PATH_PATTERN = /(?:^|[\s'"`=;|&(])((?:\.{0,2}\/|\/)[^\s'"`|;&()]+)/g;
|
|
21
30
|
const STANDALONE_COMMAND_PATTERN =
|
|
22
31
|
/(?:^|[\s;|&(])([a-z_][a-z0-9+._-]{1,})(?=$|[\s'"`|;&()])/gi;
|
|
@@ -250,7 +259,11 @@ export function createGtfoBinsProperties(name, linkedName) {
|
|
|
250
259
|
*/
|
|
251
260
|
export function createGtfoBinsPropertiesFromRow(queryCategory, row) {
|
|
252
261
|
const matches = new Map();
|
|
262
|
+
const isAccount = ACCOUNT_CATEGORIES.has(queryCategory);
|
|
253
263
|
for (const field of MATCH_FIELDS) {
|
|
264
|
+
if (isAccount && ACCOUNT_SKIPPED_FIELDS.has(field)) {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
254
267
|
const fieldValue = row?.[field];
|
|
255
268
|
if (!fieldValue) {
|
|
256
269
|
continue;
|
package/lib/inventory/hbom.js
CHANGED
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
readEnvironmentVariable,
|
|
9
9
|
recordActivity,
|
|
10
10
|
} from "../core/activity.js";
|
|
11
|
+
import { thoughtLog } from "../core/logger.js";
|
|
12
|
+
import { isCycloneDx20SpecVersion } from "./bomUtils.js";
|
|
13
|
+
import { readCycloneDx20 } from "./cyclonedx20.js";
|
|
11
14
|
import { getHbomCommandDiagnosticSummary } from "./hbomAnalysis.js";
|
|
12
15
|
import { importHbomModule } from "./hbomLoader.js";
|
|
13
16
|
import { resolveCdxgenPlugins, resolvePluginBinary } from "./plugins.js";
|
|
@@ -411,8 +414,9 @@ export function ensureSupportedHbomSpecVersion(specVersion) {
|
|
|
411
414
|
if (specVersion === undefined || specVersion === null || specVersion === "") {
|
|
412
415
|
return;
|
|
413
416
|
}
|
|
414
|
-
|
|
415
|
-
|
|
417
|
+
// cdxgen renders 2.0 itself from the 1.7 collector output.
|
|
418
|
+
if (Number(specVersion) !== 1.7 && Number(specVersion) !== 2) {
|
|
419
|
+
throw new Error("HBOM generation supports only CycloneDX 1.7 and 2.0.");
|
|
416
420
|
}
|
|
417
421
|
}
|
|
418
422
|
|
|
@@ -474,6 +478,10 @@ export function normalizeHbomOptions(options = {}) {
|
|
|
474
478
|
includeSensitiveIdentifiers:
|
|
475
479
|
options.includeSensitiveIdentifiers ?? options.sensitive ?? false,
|
|
476
480
|
platform: options.platform,
|
|
481
|
+
// Always 1.7: cdxgen's own pipeline (postProcess and its 2.0 renderer)
|
|
482
|
+
// turns the 1.7 collector output into 2.0, the way it renders every
|
|
483
|
+
// other BOM. A cdx-hbom that can emit 2.0 itself is never asked to.
|
|
484
|
+
specVersion: "1.7",
|
|
477
485
|
timeoutMs:
|
|
478
486
|
Number.isNaN(timeoutMs) || timeoutMs <= 0 ? undefined : timeoutMs,
|
|
479
487
|
};
|
|
@@ -722,6 +730,38 @@ export function addHbomAnalysisProperties(bomJson) {
|
|
|
722
730
|
return bomJson;
|
|
723
731
|
}
|
|
724
732
|
|
|
733
|
+
/**
|
|
734
|
+
* The 1.x-shaped model of a collector result. cdxgen asks the collector for
|
|
735
|
+
* 1.7; a collector that still answers with a CycloneDX 2.0 document (a
|
|
736
|
+
* `specFormat`, or specVersion 2.0) is read with readCycloneDx20, so the
|
|
737
|
+
* 1.x pipeline that follows never mistakes it for a 1.x BOM and loses its
|
|
738
|
+
* inventories.
|
|
739
|
+
*
|
|
740
|
+
* @param {object} collected What collectHardware returned
|
|
741
|
+
* @returns {object} The 1.x-shaped HBOM
|
|
742
|
+
*/
|
|
743
|
+
export function toInternalHbom(collected) {
|
|
744
|
+
if (
|
|
745
|
+
!collected ||
|
|
746
|
+
typeof collected !== "object" ||
|
|
747
|
+
!(collected.specFormat || isCycloneDx20SpecVersion(collected.specVersion))
|
|
748
|
+
) {
|
|
749
|
+
return collected;
|
|
750
|
+
}
|
|
751
|
+
const { internalBom, losses } = readCycloneDx20(collected);
|
|
752
|
+
if (losses.length) {
|
|
753
|
+
thoughtLog(
|
|
754
|
+
`The HBOM collector returned CycloneDX 2.0; reading it into the 1.x model reported ${losses.length} loss(es).`,
|
|
755
|
+
losses,
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
// The pipeline renders 2.0 again from the 1.x model, so the model says
|
|
759
|
+
// what the collector was asked for.
|
|
760
|
+
internalBom.specVersion = "1.7";
|
|
761
|
+
delete internalBom.specFormat;
|
|
762
|
+
return internalBom;
|
|
763
|
+
}
|
|
764
|
+
|
|
725
765
|
/**
|
|
726
766
|
* Generate an HBOM using the optional cdx-hbom package.
|
|
727
767
|
*
|
|
@@ -750,12 +790,11 @@ export async function createHbomDocument(options = {}) {
|
|
|
750
790
|
});
|
|
751
791
|
return createDryRunHbomDocument(options);
|
|
752
792
|
}
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
);
|
|
793
|
+
const collected = await hbomModule.collectHardware(normalizedOptions);
|
|
794
|
+
const bomJson = addHbomAnalysisProperties(toInternalHbom(collected));
|
|
756
795
|
if (isDryRun) {
|
|
757
796
|
recordHbomCollectorTrace(
|
|
758
|
-
hbomModule.getCollectorTrace?.(
|
|
797
|
+
hbomModule.getCollectorTrace?.(collected) ?? normalizedOptions.trace,
|
|
759
798
|
);
|
|
760
799
|
}
|
|
761
800
|
return bomJson;
|
|
@@ -7,6 +7,21 @@ const LOCAL_HBOM_MODULE_URL = new URL(
|
|
|
7
7
|
import.meta.url,
|
|
8
8
|
);
|
|
9
9
|
const LOCAL_HBOM_MODULE_PATH = fileURLToPath(LOCAL_HBOM_MODULE_URL);
|
|
10
|
+
// The ./cdx20 export of @cdxgen/cdx-hbom (cdx-hbom#26), at the same place
|
|
11
|
+
// relative to a local checkout as the package's exports map gives it.
|
|
12
|
+
const LOCAL_HBOM_MAPPER_PATH = fileURLToPath(
|
|
13
|
+
new URL("../../cdx-hbom/src/common/cdx20.js", import.meta.url),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The places cdx-hbom is loaded from, in order: a local checkout next to
|
|
18
|
+
* cdxgen, else the installed package.
|
|
19
|
+
*/
|
|
20
|
+
export const HBOM_MODULE_LOCATIONS = Object.freeze({
|
|
21
|
+
localModulePath: LOCAL_HBOM_MODULE_PATH,
|
|
22
|
+
localMapperPath: LOCAL_HBOM_MAPPER_PATH,
|
|
23
|
+
packageMapperSpecifier: "@cdxgen/cdx-hbom/cdx20",
|
|
24
|
+
});
|
|
10
25
|
|
|
11
26
|
/**
|
|
12
27
|
* Resolve the optional cdx-hbom module.
|
|
@@ -33,3 +48,154 @@ export async function importHbomModule() {
|
|
|
33
48
|
}
|
|
34
49
|
return hbomModule;
|
|
35
50
|
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Load the optional CycloneDX 2.0 hardware mapper,
|
|
54
|
+
* `toCdx20HardwareComponent`, from the same cdx-hbom that importHbomModule
|
|
55
|
+
* loads: the local checkout when it exists (its src/common/cdx20.js), else
|
|
56
|
+
* the installed package's `./cdx20` export. A cdx-hbom without the mapper
|
|
57
|
+
* (the published 0.7.0 has no `./cdx20` export) or one that fails to load
|
|
58
|
+
* gives null, and the 2.0 render then keeps its generic conversion.
|
|
59
|
+
*
|
|
60
|
+
* @param {object} [locations] Where to look; defaults to
|
|
61
|
+
* HBOM_MODULE_LOCATIONS
|
|
62
|
+
* @returns {Promise<Function|null>} The mapper, or null
|
|
63
|
+
*/
|
|
64
|
+
export async function loadHardwareMapper(locations = HBOM_MODULE_LOCATIONS) {
|
|
65
|
+
let specifier = locations.packageMapperSpecifier;
|
|
66
|
+
if (safeExistsSync(locations.localModulePath)) {
|
|
67
|
+
if (!safeExistsSync(locations.localMapperPath)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
specifier = pathToFileURL(locations.localMapperPath).href;
|
|
71
|
+
}
|
|
72
|
+
let mapperModule;
|
|
73
|
+
try {
|
|
74
|
+
mapperModule = await import(specifier);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
// cdx-hbom not installed, or a release without the ./cdx20 export: the
|
|
77
|
+
// generic conversion applies and nothing is wrong. Any other failure is
|
|
78
|
+
// a broken cdx-hbom and is reported before falling back.
|
|
79
|
+
if (!isMissingMapperError(err, specifier)) {
|
|
80
|
+
console.warn(
|
|
81
|
+
`The cdx-hbom CycloneDX 2.0 hardware mapper could not be loaded, so hardware components use the generic 2.0 conversion: ${err?.message || err}`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return typeof mapperModule.toCdx20HardwareComponent === "function"
|
|
87
|
+
? mapperModule.toCdx20HardwareComponent
|
|
88
|
+
: null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Whether an import error means the mapper is simply absent: the package is
|
|
93
|
+
* not installed, or its exports map has no `./cdx20`. A missing module
|
|
94
|
+
* imported from inside the mapper is a fault, not an absence.
|
|
95
|
+
*
|
|
96
|
+
* @param {Error} err Import error
|
|
97
|
+
* @param {string} specifier The specifier that was imported
|
|
98
|
+
* @returns {boolean} true when the mapper is absent
|
|
99
|
+
*/
|
|
100
|
+
function isMissingMapperError(err, specifier) {
|
|
101
|
+
if (err?.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
const message = String(err?.message || "");
|
|
105
|
+
const packageName = specifier.startsWith("@")
|
|
106
|
+
? specifier.split("/").slice(0, 2).join("/")
|
|
107
|
+
: undefined;
|
|
108
|
+
if (packageName) {
|
|
109
|
+
// Node.js and Bun name the missing package; Deno reports an import that
|
|
110
|
+
// its import map or node_modules cannot resolve.
|
|
111
|
+
return (
|
|
112
|
+
message.includes(`'${packageName}'`) ||
|
|
113
|
+
message.includes(`"${packageName}"`) ||
|
|
114
|
+
message.includes(`${packageName}/cdx20`) ||
|
|
115
|
+
(err?.code === "ERR_MODULE_NOT_FOUND" && message.includes(packageName))
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** The identifier policy cdx-hbom records when raw identifiers were kept. */
|
|
122
|
+
export const RAW_IDENTIFIER_POLICY = "raw-identifiers-enabled";
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The identifier policy the collector recorded for the run, on the HBOM
|
|
126
|
+
* subject (`metadata.component`) or in `metadata.properties`.
|
|
127
|
+
*
|
|
128
|
+
* @param {object} internalBom The 1.x-shaped internal model
|
|
129
|
+
* @returns {string|undefined} The `cdx:hbom:identifierPolicy` value
|
|
130
|
+
*/
|
|
131
|
+
export function recordedIdentifierPolicy(internalBom) {
|
|
132
|
+
for (const properties of [
|
|
133
|
+
internalBom?.metadata?.component?.properties,
|
|
134
|
+
internalBom?.metadata?.properties,
|
|
135
|
+
]) {
|
|
136
|
+
const value = (Array.isArray(properties) ? properties : []).find(
|
|
137
|
+
(property) => property?.name === "cdx:hbom:identifierPolicy",
|
|
138
|
+
)?.value;
|
|
139
|
+
if (typeof value === "string") {
|
|
140
|
+
return value;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The renderCycloneDx20 context for an internal model: the hardware mapper
|
|
148
|
+
* and its identifier options when the model has a component with a
|
|
149
|
+
* cdx:hbom:* property and a mapper is available, otherwise an empty context,
|
|
150
|
+
* so a BOM without hardware never loads cdx-hbom. Hardware identifiers are
|
|
151
|
+
* asserted only when the collector recorded `raw-identifiers-enabled` for the
|
|
152
|
+
* run (it does when HBOM generation was asked to include sensitive
|
|
153
|
+
* identifiers); a redacted run never yields identifiers, whichever command
|
|
154
|
+
* renders it.
|
|
155
|
+
*
|
|
156
|
+
* @param {object} internalBom The 1.x-shaped internal model
|
|
157
|
+
* @param {object} [locations] Passed to loadHardwareMapper
|
|
158
|
+
* @returns {Promise<{hardwareMapper?: Function, hardwareOptions?: {includeSensitiveIdentifiers: boolean, identifierPolicy?: string}}>}
|
|
159
|
+
* The render context
|
|
160
|
+
*/
|
|
161
|
+
export async function hardwareRenderContext(internalBom, locations) {
|
|
162
|
+
if (!hasHardwareComponent(internalBom)) {
|
|
163
|
+
return {};
|
|
164
|
+
}
|
|
165
|
+
const hardwareMapper = await loadHardwareMapper(locations);
|
|
166
|
+
if (!hardwareMapper) {
|
|
167
|
+
return {};
|
|
168
|
+
}
|
|
169
|
+
const identifierPolicy = recordedIdentifierPolicy(internalBom);
|
|
170
|
+
const hardwareOptions = {
|
|
171
|
+
includeSensitiveIdentifiers: identifierPolicy === RAW_IDENTIFIER_POLICY,
|
|
172
|
+
};
|
|
173
|
+
if (identifierPolicy !== undefined) {
|
|
174
|
+
hardwareOptions.identifierPolicy = identifierPolicy;
|
|
175
|
+
}
|
|
176
|
+
return { hardwareMapper, hardwareOptions };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function hasHardwareComponent(internalBom) {
|
|
180
|
+
const pending = [
|
|
181
|
+
internalBom?.metadata?.component,
|
|
182
|
+
...(Array.isArray(internalBom?.components) ? internalBom.components : []),
|
|
183
|
+
];
|
|
184
|
+
while (pending.length) {
|
|
185
|
+
const component = pending.pop();
|
|
186
|
+
if (!component || typeof component !== "object") {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (
|
|
190
|
+
(component.properties || []).some((property) =>
|
|
191
|
+
`${property?.name ?? ""}`.startsWith("cdx:hbom:"),
|
|
192
|
+
)
|
|
193
|
+
) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
if (Array.isArray(component.components)) {
|
|
197
|
+
pending.push(...component.components);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|