@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
package/lib/server/server.js
CHANGED
|
@@ -14,7 +14,10 @@ import {
|
|
|
14
14
|
isSecureMode,
|
|
15
15
|
readEnvironmentVariable,
|
|
16
16
|
} from "../core/activity.js";
|
|
17
|
+
import { PROJECT_TYPE_ALIASES } from "../core/env.js";
|
|
17
18
|
import { isWin } from "../core/paths.js";
|
|
19
|
+
import { isSecureModeActive } from "../core/projectTooling.js";
|
|
20
|
+
import { resetRunState } from "../core/runState.js";
|
|
18
21
|
import { CDXGEN_VERSION } from "../core/state.js";
|
|
19
22
|
import { installConsoleShim, ui } from "../core/ui.js";
|
|
20
23
|
import { fetchPomXmlAsJson } from "../ecosystems/ecosystems.js";
|
|
@@ -26,6 +29,7 @@ import {
|
|
|
26
29
|
getGitAllowProtocol,
|
|
27
30
|
gitClone,
|
|
28
31
|
isAllowedPath,
|
|
32
|
+
isAllowedRealPath,
|
|
29
33
|
isAllowedWinPath,
|
|
30
34
|
maybePurlSource,
|
|
31
35
|
maybeRemotePath,
|
|
@@ -81,6 +85,11 @@ const ALLOWED_PARAMS = [
|
|
|
81
85
|
"tlpClassification",
|
|
82
86
|
];
|
|
83
87
|
|
|
88
|
+
// Options that install packages or run the scanned project's own build tools
|
|
89
|
+
// (for example `cargo check`, which runs build.rs), and so execute code from
|
|
90
|
+
// the scanned repository.
|
|
91
|
+
const CODE_EXECUTION_PARAMS = ["installDeps", "deep"];
|
|
92
|
+
|
|
84
93
|
const app = connect();
|
|
85
94
|
|
|
86
95
|
export { isAllowedHttpHost };
|
|
@@ -155,6 +164,7 @@ export function parseValue(raw) {
|
|
|
155
164
|
* @returns {Object} Populated options object
|
|
156
165
|
*/
|
|
157
166
|
export function parseQueryString(q, body = {}, options = {}) {
|
|
167
|
+
const operatorOptions = { ...options };
|
|
158
168
|
// Priority is query params followed by body
|
|
159
169
|
for (const param of ALLOWED_PARAMS) {
|
|
160
170
|
const raw = q[param] ?? body[param];
|
|
@@ -162,7 +172,7 @@ export function parseQueryString(q, body = {}, options = {}) {
|
|
|
162
172
|
options[param] = parseValue(raw);
|
|
163
173
|
}
|
|
164
174
|
}
|
|
165
|
-
options.projectType = options.type
|
|
175
|
+
options.projectType = toProjectTypeList(options.type);
|
|
166
176
|
delete options.type;
|
|
167
177
|
if (options.lifecycle === "pre-build") {
|
|
168
178
|
options.installDeps = false;
|
|
@@ -170,9 +180,170 @@ export function parseQueryString(q, body = {}, options = {}) {
|
|
|
170
180
|
if (options.profile) {
|
|
171
181
|
applyProfileOptions(options);
|
|
172
182
|
}
|
|
183
|
+
// failOnError ends the process, so one failing request would stop the server
|
|
184
|
+
// for every client.
|
|
185
|
+
options.failOnError = false;
|
|
186
|
+
restrictRequestOptions(options, operatorOptions);
|
|
173
187
|
return options;
|
|
174
188
|
}
|
|
175
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Normalise a `type` value from the request or the start-up options, which may
|
|
192
|
+
* be a comma separated string or an array, into a list of project types.
|
|
193
|
+
*
|
|
194
|
+
* @param {string|string[]|undefined} type Project type value
|
|
195
|
+
* @returns {string[]|undefined} Project types, or undefined when none are given
|
|
196
|
+
*/
|
|
197
|
+
function toProjectTypeList(type) {
|
|
198
|
+
if (type === undefined || type === null || type === "") {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
const types = (Array.isArray(type) ? type : [type])
|
|
202
|
+
.flatMap((t) => String(t).split(","))
|
|
203
|
+
.map((t) => t.trim())
|
|
204
|
+
.filter(Boolean);
|
|
205
|
+
return types.length ? types : undefined;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Stop a request from turning on options that execute code from the scanned
|
|
210
|
+
* repository when the operator has not. In secure mode, or when the server was
|
|
211
|
+
* started with --no-install-deps, a request may turn these options off but
|
|
212
|
+
* never on.
|
|
213
|
+
*
|
|
214
|
+
* @param {Object} options Options parsed from the request
|
|
215
|
+
* @param {Object} operatorOptions Options the server was started with
|
|
216
|
+
* @returns {void}
|
|
217
|
+
*/
|
|
218
|
+
function restrictRequestOptions(options, operatorOptions) {
|
|
219
|
+
if (!isSecureModeActive() && operatorOptions.installDeps !== false) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
for (const param of CODE_EXECUTION_PARAMS) {
|
|
223
|
+
// Only an explicit false from the request changes the operator's choice.
|
|
224
|
+
// Values such as "" or 0 would otherwise pass gates that test `!== false`.
|
|
225
|
+
options[param] =
|
|
226
|
+
operatorOptions[param] === true && options[param] !== false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Project types that inventory the host the server runs on, such as installed
|
|
231
|
+
// packages, users, shell history, IDE and browser extensions, or the Maven,
|
|
232
|
+
// Gradle, sbt, Cargo and Helm caches in the server user's home directory.
|
|
233
|
+
// They ignore the scan path, so the path allowlist does not limit them.
|
|
234
|
+
const HOST_SCOPE_PROJECT_TYPES = new Set(
|
|
235
|
+
[
|
|
236
|
+
"os",
|
|
237
|
+
"hbom",
|
|
238
|
+
"cargo-cache",
|
|
239
|
+
"helm-index",
|
|
240
|
+
"gradle-index",
|
|
241
|
+
"sbt-index",
|
|
242
|
+
"maven-index",
|
|
243
|
+
"vscode-extension",
|
|
244
|
+
"chrome-extension",
|
|
245
|
+
"agentic",
|
|
246
|
+
]
|
|
247
|
+
.flatMap((key) => PROJECT_TYPE_ALIASES[key] || [key])
|
|
248
|
+
.concat(["maven-repo"]),
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Check request options that the server must refuse outright.
|
|
253
|
+
*
|
|
254
|
+
* @param {Object} reqOptions Options parsed from the request
|
|
255
|
+
* @param {Object} operatorOptions Options the server was started with
|
|
256
|
+
* @returns {Object|null} Error object with status, error and details, or null
|
|
257
|
+
*/
|
|
258
|
+
export function validateRequestOptions(reqOptions, operatorOptions = {}) {
|
|
259
|
+
const operatorTypes = new Set(
|
|
260
|
+
toProjectTypeList(operatorOptions.type ?? operatorOptions.projectType) ||
|
|
261
|
+
[],
|
|
262
|
+
);
|
|
263
|
+
const hostScopeType = (reqOptions.projectType || []).find(
|
|
264
|
+
(t) => HOST_SCOPE_PROJECT_TYPES.has(t) && !operatorTypes.has(t),
|
|
265
|
+
);
|
|
266
|
+
if (hostScopeType) {
|
|
267
|
+
return {
|
|
268
|
+
status: 403,
|
|
269
|
+
error: "Project Type Not Allowed",
|
|
270
|
+
details: `The '${hostScopeType}' project type scans the server host. Start the server with this type to allow it.`,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
const excludes = Array.isArray(reqOptions.exclude)
|
|
274
|
+
? reqOptions.exclude
|
|
275
|
+
: [reqOptions.exclude];
|
|
276
|
+
// Brace patterns expand before matching, so one short pattern such as
|
|
277
|
+
// {1..100000} can keep the server busy for minutes.
|
|
278
|
+
if (
|
|
279
|
+
reqOptions.exclude !== operatorOptions.exclude &&
|
|
280
|
+
excludes.some(
|
|
281
|
+
(e) => typeof e === "string" && (e.includes("{") || e.length > 512),
|
|
282
|
+
)
|
|
283
|
+
) {
|
|
284
|
+
return {
|
|
285
|
+
status: 400,
|
|
286
|
+
error: "Invalid Exclude Pattern",
|
|
287
|
+
details:
|
|
288
|
+
"Exclude patterns sent to the server cannot use braces or exceed 512 characters.",
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
if (
|
|
292
|
+
reqOptions.serverUrl &&
|
|
293
|
+
reqOptions.serverUrl !== operatorOptions.serverUrl
|
|
294
|
+
) {
|
|
295
|
+
const requestedOrigin = urlOrigin(reqOptions.serverUrl);
|
|
296
|
+
if (!requestedOrigin) {
|
|
297
|
+
return {
|
|
298
|
+
status: 400,
|
|
299
|
+
error: "Invalid Server URL",
|
|
300
|
+
details: "The Dependency-Track server URL is invalid.",
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
if (requestedOrigin !== urlOrigin(operatorOptions.serverUrl)) {
|
|
304
|
+
// The operator's API key only ever goes to the operator's server.
|
|
305
|
+
if (
|
|
306
|
+
operatorOptions.apiKey &&
|
|
307
|
+
reqOptions.apiKey === operatorOptions.apiKey
|
|
308
|
+
) {
|
|
309
|
+
return {
|
|
310
|
+
status: 400,
|
|
311
|
+
error: "API Key Required",
|
|
312
|
+
details:
|
|
313
|
+
"A request that names its own Dependency-Track server must send its own API key.",
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
// CDXGEN_SERVER_ALLOWED_HOSTS only covers git hosts, so in secure mode a
|
|
317
|
+
// server the operator did not configure must be on CDXGEN_ALLOWED_HOSTS.
|
|
318
|
+
if (isSecureMode && !readEnvironmentVariable("CDXGEN_ALLOWED_HOSTS")) {
|
|
319
|
+
return {
|
|
320
|
+
status: 403,
|
|
321
|
+
error: "Host Not Allowed",
|
|
322
|
+
details:
|
|
323
|
+
"Set CDXGEN_ALLOWED_HOSTS to let requests choose a Dependency-Track server.",
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (isSecureMode && reqOptions.includeFormulation && reqOptions.serverUrl) {
|
|
329
|
+
return {
|
|
330
|
+
status: 400,
|
|
331
|
+
error: "Formulation Not Allowed",
|
|
332
|
+
details:
|
|
333
|
+
"Formulation data may contain secrets and is not submitted to Dependency-Track in secure mode.",
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function urlOrigin(value) {
|
|
340
|
+
try {
|
|
341
|
+
return new URL(value).origin;
|
|
342
|
+
} catch (_err) {
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
176
347
|
/**
|
|
177
348
|
* Extracts query parameters from an incoming HTTP request object.
|
|
178
349
|
* Handles repeated keys by collecting their values into an array.
|
|
@@ -244,6 +415,26 @@ const configureServer = (cdxgenServer) => {
|
|
|
244
415
|
|
|
245
416
|
const ALL_INTERFACES = new Set(["0.0.0.0", "::", "::/128", "::/0"]);
|
|
246
417
|
|
|
418
|
+
// Registry answers, recorded misses and local cache lookups last for one scan.
|
|
419
|
+
// They are emptied whenever no scan is running, so a scan neither starts from
|
|
420
|
+
// an earlier scan's answers, which would hide new releases and new downloads,
|
|
421
|
+
// nor has its own emptied by a scan running alongside it.
|
|
422
|
+
let activeScans = 0;
|
|
423
|
+
|
|
424
|
+
function beginScan() {
|
|
425
|
+
if (activeScans === 0) {
|
|
426
|
+
resetRunState();
|
|
427
|
+
}
|
|
428
|
+
activeScans++;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function endScan() {
|
|
432
|
+
activeScans--;
|
|
433
|
+
if (activeScans === 0) {
|
|
434
|
+
resetRunState();
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
247
438
|
/**
|
|
248
439
|
* Boot the cdxgen HTTP server.
|
|
249
440
|
*
|
|
@@ -370,6 +561,18 @@ const start = (options) => {
|
|
|
370
561
|
}),
|
|
371
562
|
);
|
|
372
563
|
}
|
|
564
|
+
const optionsError = validateRequestOptions(reqOptions, options);
|
|
565
|
+
if (optionsError) {
|
|
566
|
+
res.writeHead(optionsError.status, {
|
|
567
|
+
"Content-Type": "application/json",
|
|
568
|
+
});
|
|
569
|
+
return res.end(
|
|
570
|
+
JSON.stringify({
|
|
571
|
+
error: optionsError.error,
|
|
572
|
+
details: optionsError.details,
|
|
573
|
+
}),
|
|
574
|
+
);
|
|
575
|
+
}
|
|
373
576
|
// Enforce the v13 CycloneDX spec floor on the HTTP entry point too, so the
|
|
374
577
|
// server cannot be used to request a generation target the CLI rejects.
|
|
375
578
|
if (reqOptions.specVersion !== undefined) {
|
|
@@ -393,6 +596,7 @@ const start = (options) => {
|
|
|
393
596
|
}
|
|
394
597
|
let cloneDir;
|
|
395
598
|
let srcDir;
|
|
599
|
+
beginScan();
|
|
396
600
|
try {
|
|
397
601
|
let sourcePath = filePath;
|
|
398
602
|
let purlResolution;
|
|
@@ -480,8 +684,11 @@ const start = (options) => {
|
|
|
480
684
|
cleanup = true;
|
|
481
685
|
} else {
|
|
482
686
|
srcDir = sourcePath;
|
|
687
|
+
// Check where a symlinked path really points as well, so a link inside
|
|
688
|
+
// an allowed directory cannot open a scan of a directory outside it.
|
|
483
689
|
if (
|
|
484
690
|
!isAllowedPath(path.resolve(srcDir)) ||
|
|
691
|
+
!isAllowedRealPath(srcDir) ||
|
|
485
692
|
(isWin && !isAllowedWinPath(srcDir))
|
|
486
693
|
) {
|
|
487
694
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
@@ -606,6 +813,7 @@ const start = (options) => {
|
|
|
606
813
|
}
|
|
607
814
|
console.log("Error while generating SBOM response", err);
|
|
608
815
|
} finally {
|
|
816
|
+
endScan();
|
|
609
817
|
if (cleanup && cloneDir) {
|
|
610
818
|
cleanupSourceDir(cloneDir);
|
|
611
819
|
}
|
|
@@ -463,6 +463,15 @@ export function textualMetadata(bomJson) {
|
|
|
463
463
|
const swidCount = bomJson?.components?.filter((c) =>
|
|
464
464
|
c?.purl?.startsWith("pkg:swid"),
|
|
465
465
|
).length;
|
|
466
|
+
// Homebrew packages are pkg:brew, not pkg:swid, so they are not counted as
|
|
467
|
+
// applications; formulae and casks are told apart by a property.
|
|
468
|
+
const brewComponents =
|
|
469
|
+
bomJson?.components?.filter((c) => c?.purl?.startsWith("pkg:brew/")) || [];
|
|
470
|
+
const brewCaskCount = brewComponents.filter((c) =>
|
|
471
|
+
c.properties?.some(
|
|
472
|
+
(p) => p.name === "cdx:homebrew:type" && p.value === "cask",
|
|
473
|
+
),
|
|
474
|
+
).length;
|
|
466
475
|
const { unpackagedExecutableCount, unpackagedSharedLibraryCount } =
|
|
467
476
|
getContainerFileInventoryStats(bomJson?.components);
|
|
468
477
|
const githubStats = getGitHubWorkflowStats(bomJson?.components);
|
|
@@ -711,7 +720,14 @@ export function textualMetadata(bomJson) {
|
|
|
711
720
|
text = `${text} The system appears to be set up for remote development, with ${vsixCount} Visual Studio Code extensions installed.`;
|
|
712
721
|
}
|
|
713
722
|
if (swidCount > 0) {
|
|
714
|
-
text = `${text} In addition, there are ${swidCount} applications installed on the system.`;
|
|
723
|
+
text = `${text} In addition, there ${swidCount === 1 ? "is 1 application" : `are ${swidCount} applications`} installed on the system.`;
|
|
724
|
+
}
|
|
725
|
+
if (brewComponents.length > 0) {
|
|
726
|
+
const brewCount = brewComponents.length;
|
|
727
|
+
const casks = brewCaskCount
|
|
728
|
+
? `, of which ${brewCaskCount} ${brewCaskCount === 1 ? "is a cask" : "are casks"}`
|
|
729
|
+
: "";
|
|
730
|
+
text = `${text} The system also has ${brewCount} Homebrew package${brewCount === 1 ? "" : "s"} installed${casks}.`;
|
|
715
731
|
}
|
|
716
732
|
}
|
|
717
733
|
if (bomType === "HBOM" && hbomSummary) {
|
|
@@ -137,7 +137,7 @@ export const ECOSYSTEM_MARKERS = Object.freeze({
|
|
|
137
137
|
ocaml: { names: ["dune-project"], suffixes: [".opam"] },
|
|
138
138
|
lua: { names: ["luarocks.lock"], suffixes: [".rockspec"] },
|
|
139
139
|
spack: { names: ["spack.yaml", "spack.lock"], suffixes: [] },
|
|
140
|
-
terraform: { names: [".terraform.lock.hcl"], suffixes: [] },
|
|
140
|
+
terraform: { names: [".terraform.lock.hcl"], suffixes: [".tf", ".tofu"] },
|
|
141
141
|
});
|
|
142
142
|
|
|
143
143
|
/** Marker file name → ecosystems claiming it, and marker suffix → claiming
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
isVersionedJvmToolProjectType,
|
|
37
37
|
PROJECT_TYPE_ALIASES,
|
|
38
38
|
} from "../../../core/env.js";
|
|
39
|
+
import { safeExistsSync } from "../../../core/fs.js";
|
|
39
40
|
import { dirNameStr } from "../../../core/paths.js";
|
|
40
41
|
import { CDXGEN_VERSION } from "../../../core/state.js";
|
|
41
42
|
import { evaluateRules, loadRules } from "../ruleEngine.js";
|
|
@@ -389,7 +390,9 @@ function resolveLedgerEvents(context) {
|
|
|
389
390
|
};
|
|
390
391
|
}
|
|
391
392
|
const sidecarPath = readEnvironmentVariable("CDXGEN_INTROSPECT_LEDGER");
|
|
392
|
-
|
|
393
|
+
// A sidecar the run could not create (the permission model denies writes
|
|
394
|
+
// outside the granted paths) holds nothing; the buffer still has the events.
|
|
395
|
+
if (sidecarPath && safeExistsSync(sidecarPath)) {
|
|
393
396
|
return { events: loadLedgerFile(sidecarPath), source: "sidecar" };
|
|
394
397
|
}
|
|
395
398
|
const events = getLedgerEvents();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
|
|
5
5
|
import { Purl } from "@cdxgen/cdx-purl";
|
|
@@ -756,6 +756,12 @@ export function applyMetadata(bomJson, options) {
|
|
|
756
756
|
return;
|
|
757
757
|
}
|
|
758
758
|
if (comp.properties) {
|
|
759
|
+
// internal:LocalNodeModulesPath is a lookup path on the scanning host.
|
|
760
|
+
// Collectors outside the JS evidence pass (caxa, scalasem) keep it, so
|
|
761
|
+
// it is removed here for every component.
|
|
762
|
+
comp.properties = comp.properties.filter(
|
|
763
|
+
(aprop) => aprop.name !== "internal:LocalNodeModulesPath",
|
|
764
|
+
);
|
|
759
765
|
for (const aprop of comp.properties) {
|
|
760
766
|
if (aprop.name === "internal:SrcFile" && aprop.value) {
|
|
761
767
|
const rdir = relativeDir(aprop.value, options);
|
|
@@ -822,7 +828,15 @@ export function applyMetadata(bomJson, options) {
|
|
|
822
828
|
}
|
|
823
829
|
collectSrcFiles(comp);
|
|
824
830
|
}
|
|
825
|
-
|
|
831
|
+
// The project's sub-components, the modules of a multi-module build, name
|
|
832
|
+
// their manifests the same way, at any depth.
|
|
833
|
+
const collectSrcFilesTree = (comp) => {
|
|
834
|
+
collectSrcFiles(comp);
|
|
835
|
+
for (const subComponent of comp?.components || []) {
|
|
836
|
+
collectSrcFilesTree(subComponent);
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
collectSrcFilesTree(bomJson.metadata?.component);
|
|
826
840
|
if (!bomJson.metadata.properties) {
|
|
827
841
|
bomJson.metadata.properties = [];
|
|
828
842
|
}
|
|
@@ -929,10 +943,10 @@ function applyCustomMetadataProperties(bomJson, options) {
|
|
|
929
943
|
export function applyStandards(bomJson, options) {
|
|
930
944
|
if (options.standard && Array.isArray(options.standard)) {
|
|
931
945
|
for (let astandard of options.standard) {
|
|
932
|
-
// See issue: #1953
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
946
|
+
// See issue: #1953. Server requests can send either separator, and on
|
|
947
|
+
// Windows both "/" and "\" separate path segments, so keep only the
|
|
948
|
+
// last segment of either kind.
|
|
949
|
+
astandard = String(astandard).split(/[\\/]/).pop();
|
|
936
950
|
const templateFile = join(
|
|
937
951
|
dirNameStr,
|
|
938
952
|
"data",
|
|
@@ -165,7 +165,18 @@ function hasProperty(obj, propName, expectedValue) {
|
|
|
165
165
|
if (expectedValue === undefined) {
|
|
166
166
|
return value !== null;
|
|
167
167
|
}
|
|
168
|
-
|
|
168
|
+
// A repeatable property (cdx:crypto:sourceType on a certificate found by
|
|
169
|
+
// several producers) matches when any of its values does.
|
|
170
|
+
return extractPropertyValues(obj, propName).includes(String(expectedValue));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function extractPropertyValues(obj, propName) {
|
|
174
|
+
if (!Array.isArray(obj?.properties)) {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
return obj.properties
|
|
178
|
+
.filter((p) => p?.name === propName && p.value !== undefined)
|
|
179
|
+
.map((p) => String(p.value));
|
|
169
180
|
}
|
|
170
181
|
|
|
171
182
|
/**
|
|
@@ -315,6 +326,9 @@ function registerCdxHelpers(expression, helpers = {}) {
|
|
|
315
326
|
expression.registerFunction("prop", (obj, propName) =>
|
|
316
327
|
extractProperty(obj, propName),
|
|
317
328
|
);
|
|
329
|
+
expression.registerFunction("propValues", (obj, propName) =>
|
|
330
|
+
extractPropertyValues(obj, propName),
|
|
331
|
+
);
|
|
318
332
|
expression.registerFunction("nullSafeProp", (obj, propName) => {
|
|
319
333
|
const value = extractProperty(obj, propName);
|
|
320
334
|
return value === null ? "" : value;
|
|
@@ -385,6 +399,13 @@ function registerCdxHelpers(expression, helpers = {}) {
|
|
|
385
399
|
expression.registerFunction("safeStr", (val) => {
|
|
386
400
|
return val === null || val === undefined ? "" : String(val).trim();
|
|
387
401
|
});
|
|
402
|
+
// End of validity in epoch milliseconds. A date-only value (2026-01-31)
|
|
403
|
+
// is valid through the end of that day in UTC; a full RFC 3339 timestamp
|
|
404
|
+
// is taken as is; anything else, or an impossible date, gives no value so
|
|
405
|
+
// the rule skips the component.
|
|
406
|
+
expression.registerFunction("certEndMillis", (val) =>
|
|
407
|
+
parseCertificateEndMillis(val),
|
|
408
|
+
);
|
|
388
409
|
expression.registerFunction("parseSizeBytes", (val) => {
|
|
389
410
|
if (val === null || val === undefined || val === "") {
|
|
390
411
|
return null;
|
|
@@ -519,6 +540,42 @@ function registerCdxHelpers(expression, helpers = {}) {
|
|
|
519
540
|
* @param {string} rulesDir - Path to directory containing .yaml rule files
|
|
520
541
|
* @returns {Promise<Array>} Array of parsed rule objects
|
|
521
542
|
*/
|
|
543
|
+
const FULL_TIMESTAMP_RE =
|
|
544
|
+
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?(Z|[+-]([01]\d|2[0-3]):[0-5]\d)$/;
|
|
545
|
+
const DATE_ONLY_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Parse a certificate notValidAfter value.
|
|
549
|
+
*
|
|
550
|
+
* @param {*} value timestamp or date-only string
|
|
551
|
+
* @returns {number|undefined} epoch milliseconds, or undefined when the value
|
|
552
|
+
* does not parse
|
|
553
|
+
*/
|
|
554
|
+
export function parseCertificateEndMillis(value) {
|
|
555
|
+
if (typeof value !== "string") {
|
|
556
|
+
return undefined;
|
|
557
|
+
}
|
|
558
|
+
const text = value.trim();
|
|
559
|
+
const dateOnly = DATE_ONLY_RE.exec(text);
|
|
560
|
+
if (dateOnly) {
|
|
561
|
+
const [year, month, day] = dateOnly.slice(1).map(Number);
|
|
562
|
+
const start = new Date(Date.UTC(year, month - 1, day));
|
|
563
|
+
if (
|
|
564
|
+
start.getUTCFullYear() !== year ||
|
|
565
|
+
start.getUTCMonth() !== month - 1 ||
|
|
566
|
+
start.getUTCDate() !== day
|
|
567
|
+
) {
|
|
568
|
+
return undefined;
|
|
569
|
+
}
|
|
570
|
+
return start.getTime() + 24 * 60 * 60 * 1000 - 1;
|
|
571
|
+
}
|
|
572
|
+
if (!FULL_TIMESTAMP_RE.test(text)) {
|
|
573
|
+
return undefined;
|
|
574
|
+
}
|
|
575
|
+
const millis = Date.parse(text);
|
|
576
|
+
return Number.isNaN(millis) ? undefined : millis;
|
|
577
|
+
}
|
|
578
|
+
|
|
522
579
|
export async function loadRules(rulesDir) {
|
|
523
580
|
const rules = [];
|
|
524
581
|
if (!safeExistsSync(rulesDir)) {
|
|
@@ -53,6 +53,17 @@ const DEPENDENCY_1_6_ONLY_FIELDS = new Set(["provides"]);
|
|
|
53
53
|
// License and license expression objects gained these attributes only in the
|
|
54
54
|
// given spec versions. CycloneDX forbids additional properties, so they must be
|
|
55
55
|
// removed when downgrading. Ref: data/bom-1.{4,5,6}.schema.json
|
|
56
|
+
// The protocol types CycloneDX 1.6 defines; 1.7 added more.
|
|
57
|
+
const SPEC_1_6_PROTOCOL_TYPES = new Set([
|
|
58
|
+
"tls",
|
|
59
|
+
"ssh",
|
|
60
|
+
"ipsec",
|
|
61
|
+
"ike",
|
|
62
|
+
"sstp",
|
|
63
|
+
"wpa",
|
|
64
|
+
"other",
|
|
65
|
+
"unknown",
|
|
66
|
+
]);
|
|
56
67
|
const LICENSE_1_5_ONLY_FIELDS = new Set(["bom-ref", "licensing", "properties"]);
|
|
57
68
|
const LICENSE_1_6_ONLY_FIELDS = new Set(["acknowledgement"]);
|
|
58
69
|
const LICENSE_EXPRESSION_1_5_ONLY_FIELDS = new Set(["bom-ref"]);
|
|
@@ -593,17 +604,68 @@ function downgradeSubjectForSpecVersion(subject, specVersion, parentKey) {
|
|
|
593
604
|
certificateProperties.certificateExtension =
|
|
594
605
|
certificateProperties.certificateFileExtension;
|
|
595
606
|
}
|
|
607
|
+
// `relatedCryptographicAssets` and `certificateExtensions` are 1.7-only;
|
|
608
|
+
// the deprecated `subjectPublicKeyRef`/`signatureAlgorithmRef` (valid in
|
|
609
|
+
// 1.6, see data/bom-1.6.schema.json) carry the same links, and the
|
|
610
|
+
// extension facts survive as `cdx:crypto:` properties.
|
|
611
|
+
const relatedAssets = certificateProperties.relatedCryptographicAssets;
|
|
612
|
+
if (Array.isArray(relatedAssets)) {
|
|
613
|
+
for (const asset of relatedAssets) {
|
|
614
|
+
if (
|
|
615
|
+
asset?.type === "publicKey" &&
|
|
616
|
+
!certificateProperties.subjectPublicKeyRef
|
|
617
|
+
) {
|
|
618
|
+
certificateProperties.subjectPublicKeyRef = asset.ref;
|
|
619
|
+
} else if (
|
|
620
|
+
asset?.type === "algorithm" &&
|
|
621
|
+
!certificateProperties.signatureAlgorithmRef
|
|
622
|
+
) {
|
|
623
|
+
certificateProperties.signatureAlgorithmRef = asset.ref;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
delete certificateProperties.relatedCryptographicAssets;
|
|
627
|
+
}
|
|
628
|
+
delete certificateProperties.certificateExtensions;
|
|
596
629
|
delete certificateProperties.serialNumber;
|
|
597
630
|
delete certificateProperties.certificateFileExtension;
|
|
598
631
|
delete certificateProperties.fingerprint;
|
|
632
|
+
} else if (
|
|
633
|
+
specVersion < 1.7 &&
|
|
634
|
+
subject.cryptoProperties?.assetType === "related-crypto-material" &&
|
|
635
|
+
subject.cryptoProperties.relatedCryptoMaterialProperties
|
|
636
|
+
) {
|
|
637
|
+
// The public-key `fingerprint` object is 1.7-only; the SPKI digest stays
|
|
638
|
+
// available as the `cdx:crypto:spkiSha256` property.
|
|
639
|
+
delete subject.cryptoProperties.relatedCryptoMaterialProperties.fingerprint;
|
|
599
640
|
}
|
|
600
641
|
if (specVersion < 1.7 && subject.cryptoProperties?.algorithmProperties) {
|
|
601
642
|
// `algorithmFamily` and `ellipticCurve` are CycloneDX 1.7 additions to
|
|
602
643
|
// cryptoProperties.algorithmProperties. 1.6 keeps the deprecated free-text
|
|
603
644
|
// `curve`, so that one is preserved. Ref: data/bom-1.6.schema.json.
|
|
604
645
|
const algorithmProperties = subject.cryptoProperties.algorithmProperties;
|
|
646
|
+
// The curve stays known through the free-text field, by its name without
|
|
647
|
+
// the registry prefix (`secg/secp256r1` is `secp256r1`).
|
|
648
|
+
if (algorithmProperties.ellipticCurve && !algorithmProperties.curve) {
|
|
649
|
+
algorithmProperties.curve = String(algorithmProperties.ellipticCurve)
|
|
650
|
+
.split("/")
|
|
651
|
+
.pop();
|
|
652
|
+
}
|
|
605
653
|
delete algorithmProperties.algorithmFamily;
|
|
606
654
|
delete algorithmProperties.ellipticCurve;
|
|
655
|
+
// `key-wrap` joined the primitive enum in 1.7.
|
|
656
|
+
if (algorithmProperties.primitive === "key-wrap") {
|
|
657
|
+
algorithmProperties.primitive = "other";
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
if (
|
|
661
|
+
specVersion < 1.7 &&
|
|
662
|
+
subject.cryptoProperties?.protocolProperties?.type &&
|
|
663
|
+
!SPEC_1_6_PROTOCOL_TYPES.has(
|
|
664
|
+
subject.cryptoProperties.protocolProperties.type,
|
|
665
|
+
)
|
|
666
|
+
) {
|
|
667
|
+
// 1.7 added protocol types such as `dtls` and `quic`.
|
|
668
|
+
subject.cryptoProperties.protocolProperties.type = "other";
|
|
607
669
|
}
|
|
608
670
|
Object.entries(subject).forEach(([key, value]) => {
|
|
609
671
|
downgradeSubjectForSpecVersion(value, specVersion, key);
|