@cdxgen/cdxgen 13.3.0 → 13.5.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 +12 -9
- package/bin/cdxgen-secure.js +15 -0
- package/bin/cdxgen.js +115 -31
- package/bin/evinse.js +23 -1
- package/bin/hbom.js +15 -7
- package/bin/repl.js +115 -0
- package/bin/sign.js +45 -15
- package/bin/tracebom.js +5 -1
- package/bin/validate.js +84 -18
- package/bin/verify.js +155 -86
- package/data/cbomosdb-queries.json +13 -1
- package/data/component-tags.json +8 -0
- package/data/helpers/init.gradle +46 -21
- package/data/queries-darwin.json +25 -1
- package/data/queries-win.json +19 -1
- package/data/queries.json +41 -0
- package/data/remediations.json +344 -1
- package/data/rules/cbom-security.yaml +235 -4
- package/data/rules/dependency-sources.yaml +67 -0
- package/data/rules/go-binaries.yaml +46 -0
- package/data/rules/golem-go.yaml +80 -0
- package/data/rules/hbom-compliance.yaml +40 -22
- package/data/rules/hbom-performance.yaml +7 -1
- package/data/rules/host-topology.yaml +1 -1
- package/data/rules/obom-runtime.yaml +31 -2
- package/data/rules/php-runtime.yaml +143 -0
- package/data/rules/scala-evidence.yaml +115 -0
- package/lib/audit/index.js +52 -6
- package/lib/cli/bomAssembly.js +28 -3
- package/lib/cli/cliOptions.js +110 -3
- package/lib/cli/index.js +186 -58
- package/lib/cli/jsBom.js +50 -29
- package/lib/cli/jvmBom.js +779 -146
- package/lib/cli/managedBom.js +1021 -261
- package/lib/cli/nativeBom.js +364 -58
- package/lib/core/activity.js +12 -0
- package/lib/core/env.js +47 -17
- package/lib/core/fs.js +31 -21
- package/lib/core/httpClient.js +233 -69
- package/lib/core/pluginRun.js +184 -0
- package/lib/core/processTree.js +100 -0
- package/lib/core/projectConfig.js +1 -0
- package/lib/core/projectTooling.js +97 -0
- package/lib/core/propertySanitizer.js +72 -0
- package/lib/core/runState.js +39 -0
- package/lib/core/toml.js +72 -0
- package/lib/ecosystems/asarutils.js +4 -2
- package/lib/ecosystems/bunutils.js +5 -7
- package/lib/ecosystems/cargoCache.js +231 -8
- package/lib/ecosystems/cmakeResolver.js +10 -21
- package/lib/ecosystems/cppBuildContext.js +631 -0
- package/lib/ecosystems/cppEvidence.js +337 -22
- package/lib/ecosystems/cppIncludeResolver.js +294 -0
- package/lib/ecosystems/denoutils.js +93 -66
- package/lib/ecosystems/ecosystems.js +1967 -788
- package/lib/ecosystems/golem.js +578 -18
- package/lib/ecosystems/gradleutils.js +340 -46
- package/lib/ecosystems/jsEvidence.js +85 -24
- package/lib/ecosystems/kosi.js +21 -4
- package/lib/ecosystems/npmutils.js +64 -0
- package/lib/ecosystems/parsers-dotnet.js +668 -153
- package/lib/ecosystems/parsers-elm.js +46 -28
- package/lib/ecosystems/parsers-gleam.js +3 -4
- package/lib/ecosystems/parsers-go.js +1283 -297
- package/lib/ecosystems/parsers-js.js +92 -26
- package/lib/ecosystems/parsers-julia.js +2 -3
- package/lib/ecosystems/parsers-jvm.js +463 -29
- package/lib/ecosystems/parsers-misc.js +405 -93
- package/lib/ecosystems/parsers-python.js +152 -20
- package/lib/ecosystems/parsers-rust.js +4 -4
- package/lib/ecosystems/parsers-terraform.js +1573 -19
- package/lib/ecosystems/pythonutils.js +102 -6
- package/lib/ecosystems/remote/huggingface.js +3 -0
- package/lib/ecosystems/rubyutils.js +73 -20
- package/lib/ecosystems/rusi.js +32 -9
- package/lib/ecosystems/sbtutils.js +243 -187
- package/lib/ecosystems/scalacliutils.js +343 -0
- package/lib/ecosystems/scalasem.js +2620 -0
- package/lib/ecosystems/terraformRegistry.js +288 -0
- package/lib/ecosystems/utils.js +2 -0
- package/lib/ecosystems/vendoredCode.js +156 -0
- package/lib/evinser/evinser.js +695 -78
- package/lib/evinser/swiftsem.js +68 -5
- package/lib/helpers/agenticToolutils.js +2 -2
- package/lib/helpers/bomSigner.js +576 -128
- package/lib/inventory/agentSkillSpec.js +17 -0
- package/lib/inventory/aiCollector.js +4 -1
- package/lib/inventory/analyzer.js +110 -127
- package/lib/inventory/apkInstalledDb.js +243 -0
- package/lib/inventory/atomUtils.js +204 -48
- package/lib/inventory/auditCategories.js +10 -3
- package/lib/inventory/buildToolRateLimit.js +144 -0
- package/lib/inventory/cacheCommands.js +2 -1
- package/lib/inventory/cacheDir.js +52 -9
- package/lib/inventory/certificates.js +2371 -0
- package/lib/inventory/cmakeBuildDirs.js +254 -0
- package/lib/inventory/communityAiConfigParser.js +4 -9
- package/lib/inventory/deps.js +507 -128
- package/lib/inventory/display.js +200 -3
- package/lib/inventory/dosai.js +747 -101
- package/lib/inventory/dosaiParsers.js +310 -15
- package/lib/inventory/dynamic.js +96 -8
- package/lib/inventory/envcontext.js +168 -5
- package/lib/inventory/evidenceUtils.js +590 -132
- package/lib/inventory/fetchBatch.js +574 -38
- package/lib/inventory/fetchDiskCache.js +597 -0
- package/lib/inventory/forgeEnricher.js +14 -5
- package/lib/inventory/formulationParsers.js +3 -2
- package/lib/inventory/goBuildInfo.js +140 -0
- package/lib/inventory/hbom.js +67 -7
- package/lib/inventory/hbomAnalysis.js +16 -0
- package/lib/inventory/hostTopology.js +21 -0
- package/lib/inventory/jvmLocalRepos.js +917 -0
- package/lib/inventory/mcpConfigParser.js +2 -3
- package/lib/inventory/osPackagePurl.js +244 -0
- package/lib/inventory/osPackageResolver.js +89 -87
- package/lib/inventory/osinfo.js +79 -31
- package/lib/inventory/osqueryTransform.js +114 -5
- package/lib/inventory/parentSelection.js +146 -0
- package/lib/inventory/phpBuildInfo.js +487 -0
- package/lib/inventory/phpHostProbe.js +641 -0
- package/lib/inventory/rootfsCerts.js +426 -0
- package/lib/inventory/rustFormulationParser.js +3 -4
- package/lib/inventory/scalaCoords.js +153 -0
- package/lib/inventory/source.js +215 -11
- package/lib/inventory/spdx.js +245 -0
- package/lib/inventory/traceRunner.js +93 -8
- package/lib/inventory/tracedCrypto.js +423 -0
- package/lib/managers/binary.js +529 -183
- package/lib/managers/docker.js +199 -44
- package/lib/managers/oci.js +24 -2
- package/lib/parsers/cmakeCache.js +69 -0
- package/lib/parsers/cmakeLists.js +16 -2
- package/lib/parsers/cmakePresets.js +400 -0
- package/lib/parsers/compileCommands.js +557 -0
- package/lib/parsers/email.js +277 -0
- package/lib/parsers/largeJson.js +34 -2
- package/lib/parsers/strictJson.js +322 -0
- package/lib/parsers/terraformConfig.js +1073 -0
- package/lib/parsers/terraformSource.js +652 -0
- package/lib/server/server.js +209 -1
- package/lib/stages/postgen/annotator.js +17 -1
- package/lib/stages/postgen/introspection/markers.js +1 -1
- package/lib/stages/postgen/introspection/reflect.js +4 -1
- package/lib/stages/postgen/postgen.js +20 -6
- package/lib/stages/postgen/ruleEngine.js +58 -1
- package/lib/stages/postgen/specVersionCompat.js +62 -0
- package/lib/stages/pregen/pregen.js +117 -5
- package/lib/validator/bomValidator.js +26 -5
- package/lib/validator/generated/runtime.mjs +13 -0
- package/lib/validator/generated/validate-1.6.mjs +26 -7
- package/lib/validator/generated/validate-1.7.mjs +31 -12
- package/lib/validator/generated/validate-2.0.mjs +30 -11
- package/lib/validator/index.js +25 -10
- package/lib/validator/reporters/json.js +1 -0
- package/package.json +23 -23
- package/types/bin/cdxgen-secure.d.ts +3 -0
- package/types/bin/cdxgen-secure.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +9 -2
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +43 -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.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +44 -1
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts +7 -4
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts +3 -1
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/activity.d.ts.map +1 -1
- package/types/lib/core/env.d.ts +27 -2
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/httpClient.d.ts +13 -8
- package/types/lib/core/httpClient.d.ts.map +1 -1
- package/types/lib/core/pluginRun.d.ts +97 -0
- package/types/lib/core/pluginRun.d.ts.map +1 -0
- package/types/lib/core/processTree.d.ts +36 -0
- package/types/lib/core/processTree.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/projectTooling.d.ts +41 -0
- package/types/lib/core/projectTooling.d.ts.map +1 -0
- package/types/lib/core/propertySanitizer.d.ts +26 -0
- package/types/lib/core/propertySanitizer.d.ts.map +1 -1
- package/types/lib/core/runState.d.ts +29 -0
- package/types/lib/core/runState.d.ts.map +1 -0
- package/types/lib/core/toml.d.ts +20 -0
- package/types/lib/core/toml.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
- package/types/lib/ecosystems/cargoCache.d.ts +12 -0
- package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
- package/types/lib/ecosystems/cmakeResolver.d.ts +5 -3
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
- package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +19 -3
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
- package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +9 -3
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts +62 -13
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/golem.d.ts +81 -1
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +59 -7
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -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/npmutils.d.ts +15 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-dotnet.d.ts +155 -5
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-go.d.ts +119 -5
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +6 -1
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts +74 -3
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +21 -59
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +57 -6
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
- package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +26 -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 +21 -1
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/ecosystems/sbtutils.d.ts +88 -2
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
- package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
- package/types/lib/ecosystems/scalasem.d.ts +311 -0
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +2 -2
- package/types/lib/ecosystems/utils.d.ts.map +1 -1
- package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
- package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +100 -8
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/swiftsem.d.ts +10 -0
- package/types/lib/evinser/swiftsem.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +80 -4
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/inventory/agentSkillSpec.d.ts +13 -0
- package/types/lib/inventory/agentSkillSpec.d.ts.map +1 -0
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/analyzer.d.ts.map +1 -1
- package/types/lib/inventory/apkInstalledDb.d.ts +42 -0
- package/types/lib/inventory/apkInstalledDb.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +96 -10
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +3 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
- package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +2 -1
- package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
- package/types/lib/inventory/cacheDir.d.ts +12 -4
- package/types/lib/inventory/cacheDir.d.ts.map +1 -1
- package/types/lib/inventory/certificates.d.ts +205 -0
- package/types/lib/inventory/certificates.d.ts.map +1 -0
- package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
- package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/deps.d.ts +61 -2
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/display.d.ts +18 -0
- package/types/lib/inventory/display.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +202 -14
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dosaiParsers.d.ts +53 -7
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts +16 -1
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/envcontext.d.ts +40 -2
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts +48 -14
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/fetchBatch.d.ts +83 -14
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
- package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
- package/types/lib/inventory/goBuildInfo.d.ts +10 -0
- package/types/lib/inventory/goBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -1
- package/types/lib/inventory/hbomAnalysis.d.ts +10 -0
- package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -1
- package/types/lib/inventory/hostTopology.d.ts.map +1 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/osPackagePurl.d.ts +99 -0
- package/types/lib/inventory/osPackagePurl.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +6 -2
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
- package/types/lib/inventory/osinfo.d.ts +31 -6
- package/types/lib/inventory/osinfo.d.ts.map +1 -1
- package/types/lib/inventory/osqueryTransform.d.ts +51 -0
- package/types/lib/inventory/osqueryTransform.d.ts.map +1 -1
- package/types/lib/inventory/parentSelection.d.ts +34 -0
- package/types/lib/inventory/parentSelection.d.ts.map +1 -0
- package/types/lib/inventory/phpBuildInfo.d.ts +142 -0
- package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/phpHostProbe.d.ts +35 -0
- package/types/lib/inventory/phpHostProbe.d.ts.map +1 -0
- package/types/lib/inventory/rootfsCerts.d.ts +27 -0
- package/types/lib/inventory/rootfsCerts.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/scalaCoords.d.ts +80 -0
- package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +28 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/spdx.d.ts +24 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -1
- package/types/lib/inventory/traceRunner.d.ts +16 -1
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/inventory/tracedCrypto.d.ts +64 -0
- package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
- package/types/lib/managers/binary.d.ts +10 -0
- 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/managers/oci.d.ts +3 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/parsers/cmakeCache.d.ts +16 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
- package/types/lib/parsers/cmakeLists.d.ts +2 -1
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -1
- package/types/lib/parsers/cmakePresets.d.ts +78 -0
- package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
- package/types/lib/parsers/compileCommands.d.ts +115 -0
- package/types/lib/parsers/compileCommands.d.ts.map +1 -0
- package/types/lib/parsers/email.d.ts +19 -0
- package/types/lib/parsers/email.d.ts.map +1 -0
- package/types/lib/parsers/largeJson.d.ts +13 -0
- package/types/lib/parsers/largeJson.d.ts.map +1 -1
- package/types/lib/parsers/strictJson.d.ts +46 -0
- package/types/lib/parsers/strictJson.d.ts.map +1 -0
- package/types/lib/parsers/terraformConfig.d.ts +70 -0
- package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
- package/types/lib/parsers/terraformSource.d.ts +66 -0
- package/types/lib/parsers/terraformSource.d.ts.map +1 -0
- package/types/lib/server/server.d.ts +8 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts +7 -4
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/stages/pregen/pregen.d.ts +14 -1
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +8 -0
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import {
|
|
3
|
+
basename,
|
|
4
|
+
dirname,
|
|
5
|
+
isAbsolute,
|
|
6
|
+
relative,
|
|
7
|
+
resolve,
|
|
8
|
+
sep,
|
|
9
|
+
win32,
|
|
10
|
+
} from "node:path";
|
|
11
|
+
|
|
1
12
|
import { Purl } from "@cdxgen/cdx-purl";
|
|
2
13
|
|
|
14
|
+
import { safeExistsSync } from "../core/fs.js";
|
|
15
|
+
|
|
3
16
|
/**
|
|
4
17
|
* Build a lowercase type/namespace/name lookup key for a purl.
|
|
5
18
|
*
|
|
@@ -73,6 +86,62 @@ function dosaiSourceLineNumber(item) {
|
|
|
73
86
|
return location?.LineNumber || item?.LineNumber;
|
|
74
87
|
}
|
|
75
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Format the `file#line` location of a dosai MethodCalls row, relative to the
|
|
91
|
+
* scanned directory like dosai's source rows.
|
|
92
|
+
*
|
|
93
|
+
* A call site found in assembly IL names its file through the PDB. dosai 5
|
|
94
|
+
* writes it relative to the scan root and leaves Path out when the file has
|
|
95
|
+
* no place in the tree; dosai 4 writes the PDB path as it is: absolute for a
|
|
96
|
+
* local build, `/_/` for a deterministic one (owasp-dep-scan/dosai#79). An
|
|
97
|
+
* absolute path under the scanned directory is made relative to it, and any
|
|
98
|
+
* other build path, or a missing one, gives way to the file name, as for call
|
|
99
|
+
* graph edges, so both versions list a call site found in source and in IL
|
|
100
|
+
* once. Where no sequence point covers a call, the row names the assembly and
|
|
101
|
+
* its line is an IL offset, which is no source location.
|
|
102
|
+
*
|
|
103
|
+
* @param {Object} methodCall Dosai MethodCalls row
|
|
104
|
+
* @param {string} [srcPath] Directory dosai analyzed
|
|
105
|
+
* @returns {string|undefined} Location string, or undefined when the row names no source file
|
|
106
|
+
*/
|
|
107
|
+
export function dosaiCallSiteLocation(methodCall, srcPath) {
|
|
108
|
+
const file = dosaiCallSiteFile(methodCall, srcPath);
|
|
109
|
+
const lowerFile = file?.toLowerCase();
|
|
110
|
+
if (!file || lowerFile.endsWith(".dll") || lowerFile.endsWith(".exe")) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
const lineNumber = methodCall?.LineNumber;
|
|
114
|
+
return lineNumber > 0 ? `${file}#${lineNumber}` : file;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function dosaiCallSiteFile(methodCall, srcPath) {
|
|
118
|
+
const filePath = methodCall?.Path;
|
|
119
|
+
if (filePath && filePath !== "<unknown>") {
|
|
120
|
+
if (!isAbsolute(filePath) && !win32.isAbsolute(filePath)) {
|
|
121
|
+
return filePath;
|
|
122
|
+
}
|
|
123
|
+
if (srcPath && isAbsolute(filePath)) {
|
|
124
|
+
const relativePath = relative(resolve(srcPath), filePath);
|
|
125
|
+
if (
|
|
126
|
+
relativePath &&
|
|
127
|
+
relativePath !== ".." &&
|
|
128
|
+
!relativePath.startsWith(`..${sep}`) &&
|
|
129
|
+
!isAbsolute(relativePath)
|
|
130
|
+
) {
|
|
131
|
+
return relativePath;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const fileName = methodCall?.FileName || filePath;
|
|
136
|
+
if (!fileName || fileName === "<unknown>") {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
// dosai 4 kept a Windows build's whole path as the file name on Linux.
|
|
140
|
+
return fileName.slice(
|
|
141
|
+
Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\")) + 1,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
76
145
|
/**
|
|
77
146
|
* Return a validated source location for .NET source extensions, from a call graph node.
|
|
78
147
|
*
|
|
@@ -111,44 +180,270 @@ export function dosaiSourceLocation(location) {
|
|
|
111
180
|
return sourceLocation;
|
|
112
181
|
}
|
|
113
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Split a purl into its version-free identity key and its version.
|
|
185
|
+
*
|
|
186
|
+
* @param {string} purl Package URL string
|
|
187
|
+
* @returns {{key: string, version: (string|undefined)}|undefined} Parts, or undefined for an empty input
|
|
188
|
+
*/
|
|
189
|
+
function dosaiPurlParts(purl) {
|
|
190
|
+
const key = normalizeDosaiPurlKey(purl);
|
|
191
|
+
if (!key) {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
let version;
|
|
195
|
+
try {
|
|
196
|
+
version = Purl.parse(purl).version || undefined;
|
|
197
|
+
} catch (_err) {
|
|
198
|
+
const at = purl.split("?")[0].split("#")[0].lastIndexOf("@");
|
|
199
|
+
version = at > 0 ? purl.slice(at + 1).split("?")[0] : undefined;
|
|
200
|
+
}
|
|
201
|
+
return { key, version };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* The manifests a component was identified from, as recorded in its
|
|
206
|
+
* `internal:SrcFile` values.
|
|
207
|
+
*
|
|
208
|
+
* @param {Object} component BOM component
|
|
209
|
+
* @returns {string[]} Manifest paths as recorded
|
|
210
|
+
*/
|
|
211
|
+
function componentSrcFiles(component) {
|
|
212
|
+
const files = new Set();
|
|
213
|
+
for (const property of component?.properties || []) {
|
|
214
|
+
if (property?.name === "internal:SrcFile" && property.value) {
|
|
215
|
+
files.add(`${property.value}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return [...files];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Resolve a recorded manifest path. A BOM records it relative to the scanned
|
|
223
|
+
* directory, a scan in progress as found; a relative path that does not exist
|
|
224
|
+
* under the scanned directory is tried against the working directory.
|
|
225
|
+
*
|
|
226
|
+
* @param {string} file Manifest path as recorded
|
|
227
|
+
* @param {string} [srcPath] Scanned directory
|
|
228
|
+
* @returns {string} Absolute manifest path
|
|
229
|
+
*/
|
|
230
|
+
function resolveManifestPath(file, srcPath) {
|
|
231
|
+
if (isAbsolute(file)) {
|
|
232
|
+
return file;
|
|
233
|
+
}
|
|
234
|
+
const fromSrcPath = resolve(srcPath || ".", file);
|
|
235
|
+
if (!srcPath || safeExistsSync(fromSrcPath)) {
|
|
236
|
+
return fromSrcPath;
|
|
237
|
+
}
|
|
238
|
+
const fromCwd = resolve(file);
|
|
239
|
+
return safeExistsSync(fromCwd) ? fromCwd : fromSrcPath;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* The project directory a .NET manifest belongs to. A project.assets.json
|
|
244
|
+
* names its project, which an artifacts layout keeps outside the `obj/`
|
|
245
|
+
* holding the file; otherwise it sits in the project's `obj/`, and the other
|
|
246
|
+
* manifests in the project directory.
|
|
247
|
+
*
|
|
248
|
+
* @param {string} file Absolute manifest path
|
|
249
|
+
* @returns {string} Absolute project directory
|
|
250
|
+
*/
|
|
251
|
+
function manifestProjectDir(file) {
|
|
252
|
+
const dir = dirname(file);
|
|
253
|
+
if (basename(file).toLowerCase() === "project.assets.json") {
|
|
254
|
+
try {
|
|
255
|
+
const projectPath = JSON.parse(readFileSync(file, "utf-8"))?.project
|
|
256
|
+
?.restore?.projectPath;
|
|
257
|
+
const projectDir = projectPath && dirname(resolve(projectPath));
|
|
258
|
+
if (projectDir && safeExistsSync(projectDir)) {
|
|
259
|
+
return projectDir;
|
|
260
|
+
}
|
|
261
|
+
} catch (_err) {
|
|
262
|
+
// An unreadable file falls back to its location
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return basename(dir) === "obj" ? dirname(dir) : dir;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* The project directories a candidate's manifests belong to, worked out on
|
|
270
|
+
* first use: only a record that names a version the BOM lacks, of a package
|
|
271
|
+
* the BOM holds in several versions, needs them.
|
|
272
|
+
*
|
|
273
|
+
* @param {Object} candidate Candidate built by buildDosaiPurlAliasMap
|
|
274
|
+
* @param {Map<string, string>} purlAliasMap Alias map carrying srcPath and the directory cache
|
|
275
|
+
* @returns {string[]} Absolute project directories
|
|
276
|
+
*/
|
|
277
|
+
function candidateProjectDirs(candidate, purlAliasMap) {
|
|
278
|
+
if (!candidate.projectDirs) {
|
|
279
|
+
const dirs = new Set();
|
|
280
|
+
for (const file of candidate.srcFiles) {
|
|
281
|
+
const path = resolveManifestPath(file, purlAliasMap?.srcPath);
|
|
282
|
+
let dir = purlAliasMap?.projectDirCache?.get(path);
|
|
283
|
+
if (!dir) {
|
|
284
|
+
dir = manifestProjectDir(path);
|
|
285
|
+
purlAliasMap?.projectDirCache?.set(path, dir);
|
|
286
|
+
}
|
|
287
|
+
dirs.add(dir);
|
|
288
|
+
}
|
|
289
|
+
candidate.projectDirs = [...dirs];
|
|
290
|
+
}
|
|
291
|
+
return candidate.projectDirs;
|
|
292
|
+
}
|
|
293
|
+
|
|
114
294
|
/**
|
|
115
295
|
* Build a purl alias map from BOM components.
|
|
116
296
|
*
|
|
117
|
-
* Maps
|
|
118
|
-
*
|
|
297
|
+
* Maps each component purl to itself, and indexes the components by their
|
|
298
|
+
* version-free identity, so a dosai-reported purl can be reconciled by version
|
|
299
|
+
* (see {@link resolveDosaiComponentPurl}). Two versions of one package are two
|
|
300
|
+
* components, and nothing here picks one of them on a name alone.
|
|
119
301
|
*
|
|
120
302
|
* @param {Object[]} [components] Component objects with purl fields
|
|
121
|
-
* @
|
|
303
|
+
* @param {Object} [options] Options
|
|
304
|
+
* @param {string} [options.srcPath] Directory dosai analyzed, which its relative locations
|
|
305
|
+
* and the BOM's relative manifest paths are relative to
|
|
306
|
+
* @returns {Map<string, string>} Map of purl to canonical component purl, carrying the identity index
|
|
122
307
|
*/
|
|
123
|
-
export function buildDosaiPurlAliasMap(components = []) {
|
|
308
|
+
export function buildDosaiPurlAliasMap(components = [], options = {}) {
|
|
124
309
|
const purlAliasMap = new Map();
|
|
310
|
+
const candidatesByKey = new Map();
|
|
125
311
|
for (const component of components) {
|
|
126
312
|
if (!component?.purl) {
|
|
127
313
|
continue;
|
|
128
314
|
}
|
|
129
315
|
purlAliasMap.set(component.purl, component.purl);
|
|
130
|
-
const
|
|
131
|
-
if (
|
|
132
|
-
|
|
316
|
+
const parts = dosaiPurlParts(component.purl);
|
|
317
|
+
if (!parts) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const candidates = candidatesByKey.get(parts.key) || [];
|
|
321
|
+
const existing = candidates.find(
|
|
322
|
+
(candidate) => candidate.purl === component.purl,
|
|
323
|
+
);
|
|
324
|
+
if (existing) {
|
|
325
|
+
for (const file of componentSrcFiles(component)) {
|
|
326
|
+
if (!existing.srcFiles.includes(file)) {
|
|
327
|
+
existing.srcFiles.push(file);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
} else {
|
|
331
|
+
candidates.push({
|
|
332
|
+
purl: component.purl,
|
|
333
|
+
version: parts.version,
|
|
334
|
+
srcFiles: componentSrcFiles(component),
|
|
335
|
+
});
|
|
133
336
|
}
|
|
337
|
+
candidatesByKey.set(parts.key, candidates);
|
|
134
338
|
}
|
|
339
|
+
purlAliasMap.candidatesByKey = candidatesByKey;
|
|
340
|
+
purlAliasMap.srcPath = options.srcPath;
|
|
341
|
+
purlAliasMap.projectDirCache = new Map();
|
|
135
342
|
return purlAliasMap;
|
|
136
343
|
}
|
|
137
344
|
|
|
138
345
|
/**
|
|
139
|
-
*
|
|
346
|
+
* The candidate whose project directory is the nearest one holding a file.
|
|
347
|
+
*
|
|
348
|
+
* @param {Object[]} candidates Candidates of one package identity
|
|
349
|
+
* @param {string} location Location string (`path` or `path#line`), relative to srcPath or absolute
|
|
350
|
+
* @param {Map<string, string>} purlAliasMap Alias map built by buildDosaiPurlAliasMap
|
|
351
|
+
* @returns {string|undefined} Candidate purl, or undefined when no single candidate is nearest
|
|
352
|
+
*/
|
|
353
|
+
function candidateForLocation(candidates, location, purlAliasMap) {
|
|
354
|
+
if (!location) {
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
const file = resolve(
|
|
358
|
+
purlAliasMap?.srcPath || ".",
|
|
359
|
+
`${location}`.split("#")[0],
|
|
360
|
+
);
|
|
361
|
+
let best;
|
|
362
|
+
let bestLength = -1;
|
|
363
|
+
let tied = false;
|
|
364
|
+
for (const candidate of candidates) {
|
|
365
|
+
for (const dir of candidateProjectDirs(candidate, purlAliasMap)) {
|
|
366
|
+
if (file !== dir && !file.startsWith(`${dir}${sep}`)) {
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (dir.length > bestLength) {
|
|
370
|
+
best = candidate.purl;
|
|
371
|
+
bestLength = dir.length;
|
|
372
|
+
tied = false;
|
|
373
|
+
} else if (dir.length === bestLength && best !== candidate.purl) {
|
|
374
|
+
tied = true;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return tied ? undefined : best;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Choose among the components that share a file name (two versions of a
|
|
383
|
+
* package ship the same DLLs): the only one, else the one whose project
|
|
384
|
+
* directory is nearest the record's location.
|
|
385
|
+
*
|
|
386
|
+
* @param {Iterable<string>} purls Candidate component purls
|
|
387
|
+
* @param {Map<string, string>} purlAliasMap Alias map built by buildDosaiPurlAliasMap
|
|
388
|
+
* @param {string} [location] Source location of the dosai record (`path` or `path#line`)
|
|
389
|
+
* @returns {string|undefined} The component purl, or undefined when it cannot be told
|
|
390
|
+
*/
|
|
391
|
+
export function pickDosaiComponentByLocation(purls, purlAliasMap, location) {
|
|
392
|
+
const wanted = new Set(purls);
|
|
393
|
+
if (wanted.size <= 1) {
|
|
394
|
+
return [...wanted][0];
|
|
395
|
+
}
|
|
396
|
+
const candidates = [];
|
|
397
|
+
for (const list of purlAliasMap?.candidatesByKey?.values() || []) {
|
|
398
|
+
for (const candidate of list) {
|
|
399
|
+
if (wanted.has(candidate.purl)) {
|
|
400
|
+
candidates.push(candidate);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return candidateForLocation(candidates, location, purlAliasMap);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Resolve a dosai-reported purl to a BOM component purl.
|
|
409
|
+
*
|
|
410
|
+
* The exact purl wins, then the same package at the same version (ids compare
|
|
411
|
+
* case-insensitively). A versionless purl, or a version the BOM does not hold,
|
|
412
|
+
* maps to the package's only component when it has one. When the BOM holds
|
|
413
|
+
* several versions, the record's location picks the version of the project
|
|
414
|
+
* that file belongs to; without a location that settles it the purl maps to
|
|
415
|
+
* nothing rather than to an arbitrary version (issue dosai#72).
|
|
140
416
|
*
|
|
141
417
|
* @param {string} purl Purl reported by dosai
|
|
142
418
|
* @param {Map<string, string>} purlAliasMap Alias map built by buildDosaiPurlAliasMap
|
|
143
|
-
* @
|
|
419
|
+
* @param {string} [location] Source location of the dosai record (`path` or `path#line`)
|
|
420
|
+
* @returns {string|undefined} Canonical component purl, the input purl when the BOM has no
|
|
421
|
+
* component of that package, or undefined when empty or ambiguous
|
|
144
422
|
*/
|
|
145
|
-
export function resolveDosaiComponentPurl(purl, purlAliasMap) {
|
|
423
|
+
export function resolveDosaiComponentPurl(purl, purlAliasMap, location) {
|
|
146
424
|
if (!purl) {
|
|
147
425
|
return undefined;
|
|
148
426
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
);
|
|
427
|
+
const exact = purlAliasMap?.get(purl);
|
|
428
|
+
if (exact) {
|
|
429
|
+
return exact;
|
|
430
|
+
}
|
|
431
|
+
const parts = dosaiPurlParts(purl);
|
|
432
|
+
const candidates = parts && purlAliasMap?.candidatesByKey?.get(parts.key);
|
|
433
|
+
if (!candidates?.length) {
|
|
434
|
+
return purl;
|
|
435
|
+
}
|
|
436
|
+
if (parts.version) {
|
|
437
|
+
const sameVersion = candidates.filter(
|
|
438
|
+
(candidate) =>
|
|
439
|
+
candidate.version?.toLowerCase() === parts.version.toLowerCase(),
|
|
440
|
+
);
|
|
441
|
+
if (sameVersion.length === 1) {
|
|
442
|
+
return sameVersion[0].purl;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (candidates.length === 1) {
|
|
446
|
+
return candidates[0].purl;
|
|
447
|
+
}
|
|
448
|
+
return candidateForLocation(candidates, location, purlAliasMap);
|
|
154
449
|
}
|
package/lib/inventory/dynamic.js
CHANGED
|
@@ -4,8 +4,37 @@ import { checksumFile } from "../core/fs.js";
|
|
|
4
4
|
import { mapWithConcurrency } from "../core/parallel.js";
|
|
5
5
|
import { resolvePackageForFile } from "./osPackageResolver.js";
|
|
6
6
|
import { applyPurl, tryBuildPurl } from "./purl.js";
|
|
7
|
+
import {
|
|
8
|
+
cryptoLibrariesByPath,
|
|
9
|
+
normalizeTracedCryptoComponents,
|
|
10
|
+
observedChainComponents,
|
|
11
|
+
} from "./tracedCrypto.js";
|
|
7
12
|
import { executeAndTrace, groupHttpEntriesToServices } from "./traceRunner.js";
|
|
8
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Converts a traced library path into a purl subpath. Windows paths
|
|
16
|
+
* ("C:\Windows\System32\bcrypt.dll", "\\server\share\x.dll") use forward
|
|
17
|
+
* slashes and drop the drive or UNC prefix, which a purl subpath cannot carry;
|
|
18
|
+
* the full path stays in the cdx:dynamic:filePath property.
|
|
19
|
+
*
|
|
20
|
+
* @param {string} libPath - Absolute path of the loaded library
|
|
21
|
+
* @returns {string|null} Subpath without leading separators, or null
|
|
22
|
+
*/
|
|
23
|
+
export function librarySubpath(libPath) {
|
|
24
|
+
if (!libPath) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
let subpath = libPath;
|
|
28
|
+
const isDrivePath = /^[A-Za-z]:[\\/]/.test(subpath);
|
|
29
|
+
if (isDrivePath || subpath.startsWith("\\\\")) {
|
|
30
|
+
subpath = subpath.replaceAll("\\", "/");
|
|
31
|
+
if (isDrivePath) {
|
|
32
|
+
subpath = subpath.substring(3);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return subpath.replace(/^\/+/, "") || null;
|
|
36
|
+
}
|
|
37
|
+
|
|
9
38
|
/**
|
|
10
39
|
* Builds a flat list of CycloneDX component objects and services by executing
|
|
11
40
|
* the given command and inspecting which shared libraries it loads at runtime
|
|
@@ -21,10 +50,14 @@ import { executeAndTrace, groupHttpEntriesToServices } from "./traceRunner.js";
|
|
|
21
50
|
* Services are detected from HTTP request URLs collected during tracing and
|
|
22
51
|
* follow the CycloneDX service schema with endpoints.
|
|
23
52
|
*
|
|
53
|
+
* The certificate chains servers presented in TLS ≤ 1.2 handshakes become the
|
|
54
|
+
* shared certificate model, with `provides` edges from the TLS protocol
|
|
55
|
+
* components.
|
|
56
|
+
*
|
|
24
57
|
* @param {string} commandStr - Shell command to execute and trace (e.g. "node --version")
|
|
25
58
|
* @param {string} workingDir - Working directory for the traced process
|
|
26
59
|
* @param {Object} [traceOptions] - Additional sandbox options forwarded to executeAndTrace
|
|
27
|
-
* @returns {Promise<{components: Array<Object>, services: Array<Object>}>} Components and
|
|
60
|
+
* @returns {Promise<{components: Array<Object>, services: Array<Object>, dependencies: Array<Object>}>} Components, services and dependencies
|
|
28
61
|
*/
|
|
29
62
|
export async function buildDynamicComponents(
|
|
30
63
|
commandStr,
|
|
@@ -32,7 +65,12 @@ export async function buildDynamicComponents(
|
|
|
32
65
|
traceOptions = {},
|
|
33
66
|
) {
|
|
34
67
|
const result = await executeAndTrace(commandStr, workingDir, traceOptions);
|
|
35
|
-
|
|
68
|
+
// A crypto library is a loaded library too, even when library tracing
|
|
69
|
+
// missed it.
|
|
70
|
+
const cryptoLibraries = cryptoLibrariesByPath(result.cryptoEntries);
|
|
71
|
+
const libPaths = Array.from(
|
|
72
|
+
new Set([...(result.libPaths || []), ...cryptoLibraries.keys()]),
|
|
73
|
+
);
|
|
36
74
|
const httpAccessEntries = result.httpAccessEntries || [];
|
|
37
75
|
const egressEntries = result.egressEntries || [];
|
|
38
76
|
const cryptoComponents = result.cryptoComponents || [];
|
|
@@ -50,7 +88,10 @@ export async function buildDynamicComponents(
|
|
|
50
88
|
}
|
|
51
89
|
|
|
52
90
|
const pkgInfo = resolvePackageForFile(libPath);
|
|
53
|
-
|
|
91
|
+
const cryptoLibrary = cryptoLibraries.get(libPath);
|
|
92
|
+
// The subpath uses forward slashes, so this also names a Windows DLL
|
|
93
|
+
// correctly when the BOM is built on another host.
|
|
94
|
+
let name = basename(librarySubpath(libPath) || libPath);
|
|
54
95
|
let version = "";
|
|
55
96
|
let purlStr = "";
|
|
56
97
|
let confidence = 0.5;
|
|
@@ -71,12 +112,16 @@ export async function buildDynamicComponents(
|
|
|
71
112
|
qualifiers: pkgInfo.arch ? { arch: pkgInfo.arch } : null,
|
|
72
113
|
});
|
|
73
114
|
} else {
|
|
115
|
+
// A crypto library's version is its file version (Windows reports one
|
|
116
|
+
// for each DLL it classifies).
|
|
117
|
+
version = cryptoLibrary?.version || "";
|
|
74
118
|
// Fall back to a generic purl carrying the file path as a subpath. It was
|
|
75
119
|
// previously a `path` qualifier, which generic does not permit.
|
|
76
120
|
purlStr = tryBuildPurl({
|
|
77
121
|
type: "generic",
|
|
78
122
|
name: name,
|
|
79
|
-
|
|
123
|
+
version: version || null,
|
|
124
|
+
subpath: librarySubpath(libPath),
|
|
80
125
|
});
|
|
81
126
|
}
|
|
82
127
|
|
|
@@ -117,6 +162,12 @@ export async function buildDynamicComponents(
|
|
|
117
162
|
if (version) {
|
|
118
163
|
component.version = version;
|
|
119
164
|
}
|
|
165
|
+
if (cryptoLibrary) {
|
|
166
|
+
component.properties.push({
|
|
167
|
+
name: "cdx:dynamic:cryptoLibrary",
|
|
168
|
+
value: cryptoLibrary.name,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
120
171
|
// applyPurl sets a unique fallback bom-ref when no valid purl exists, so a
|
|
121
172
|
// library that cannot be expressed as a purl still participates correctly in
|
|
122
173
|
// the dependency graph.
|
|
@@ -126,9 +177,41 @@ export async function buildDynamicComponents(
|
|
|
126
177
|
}
|
|
127
178
|
|
|
128
179
|
// Append cryptographic assets
|
|
129
|
-
|
|
180
|
+
const normalizedCryptoComponents =
|
|
181
|
+
normalizeTracedCryptoComponents(cryptoComponents);
|
|
182
|
+
// The chains servers presented in TLS ≤ 1.2 handshakes become the shared
|
|
183
|
+
// certificate model, linked from the TLS protocol components.
|
|
184
|
+
const protocolRefs = new Set(
|
|
185
|
+
normalizedCryptoComponents
|
|
186
|
+
.filter((comp) => comp.cryptoProperties?.assetType === "protocol")
|
|
187
|
+
.map((comp) => comp["bom-ref"]),
|
|
188
|
+
);
|
|
189
|
+
const observedModel = observedChainComponents(
|
|
190
|
+
result.cryptoResult,
|
|
191
|
+
protocolRefs,
|
|
192
|
+
);
|
|
193
|
+
// The traced CBOM names post-quantum algorithms after crypto-oid.json
|
|
194
|
+
// (ml-dsa-44) while the certificate model follows PLAN section 2.5
|
|
195
|
+
// (ML-DSA-44); one OID must still be one component, and the certificates
|
|
196
|
+
// reference the model's name, so a traced duplicate yields to it.
|
|
197
|
+
const observedAlgorithmOids = new Set(
|
|
198
|
+
observedModel.components
|
|
199
|
+
.filter((comp) => comp.cryptoProperties?.assetType === "algorithm")
|
|
200
|
+
.map((comp) => comp.cryptoProperties.oid),
|
|
201
|
+
);
|
|
202
|
+
for (const comp of normalizedCryptoComponents) {
|
|
203
|
+
if (
|
|
204
|
+
comp.cryptoProperties?.assetType === "algorithm" &&
|
|
205
|
+
observedAlgorithmOids.has(comp.cryptoProperties.oid)
|
|
206
|
+
) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
components.push(comp);
|
|
210
|
+
}
|
|
211
|
+
for (const comp of observedModel.components) {
|
|
130
212
|
components.push(comp);
|
|
131
213
|
}
|
|
214
|
+
const dependencies = observedModel.dependencies;
|
|
132
215
|
|
|
133
216
|
// Build services from collected HTTP URLs
|
|
134
217
|
const servicesMap = groupHttpEntriesToServices(httpAccessEntries);
|
|
@@ -136,7 +219,7 @@ export async function buildDynamicComponents(
|
|
|
136
219
|
const entry = servicesMap[serviceName];
|
|
137
220
|
return {
|
|
138
221
|
name: serviceName,
|
|
139
|
-
|
|
222
|
+
"bom-ref": `urn:service:dynamic:${serviceName}`,
|
|
140
223
|
endpoints: Array.from(entry.endpoints).sort(),
|
|
141
224
|
properties: entry.properties,
|
|
142
225
|
};
|
|
@@ -154,7 +237,7 @@ export async function buildDynamicComponents(
|
|
|
154
237
|
if (!svc) {
|
|
155
238
|
svc = {
|
|
156
239
|
name,
|
|
157
|
-
|
|
240
|
+
"bom-ref": `urn:service:dynamic:${name}`,
|
|
158
241
|
endpoints: [],
|
|
159
242
|
properties: [],
|
|
160
243
|
};
|
|
@@ -179,5 +262,10 @@ export async function buildDynamicComponents(
|
|
|
179
262
|
}
|
|
180
263
|
}
|
|
181
264
|
|
|
182
|
-
return {
|
|
265
|
+
return {
|
|
266
|
+
components,
|
|
267
|
+
services,
|
|
268
|
+
dependencies,
|
|
269
|
+
dryRunSummary: result.dryRunSummary,
|
|
270
|
+
};
|
|
183
271
|
}
|