@cdxgen/cdxgen 13.5.0 → 13.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -10
- package/bin/audit.js +7 -4
- package/bin/cdxgen.js +260 -37
- package/bin/convert.js +146 -22
- package/bin/evinse.js +28 -3
- package/bin/repl.js +47 -3
- package/bin/sign.js +211 -34
- package/bin/tracebom.js +18 -6
- package/bin/validate.js +24 -3
- package/bin/verify.js +113 -5
- package/data/behavior-taxonomy.schema.json +1491 -0
- package/data/cyclonedx-2.0-bundled.schema.json +18606 -5528
- package/data/cyclonedx-2.0-cryptography-defs.schema.json +857 -0
- package/data/license-aliases.json +24 -2
- package/data/pqc-migration.json +239 -0
- package/data/remediations.json +176 -0
- package/data/rules/ai-bom.yaml +1 -1
- package/data/rules/brotli-decoder.yaml +107 -0
- package/data/rules/cbom-security.yaml +4 -3
- package/data/rules/package-integrity.yaml +28 -0
- package/data/rules/vscode-extensions.yaml +75 -0
- package/data/spdx-license-list.json +121 -7
- package/data/spdx-licenses.json +69 -0
- package/data/spdx.schema.json +845 -2
- package/lib/audit/index.js +25 -3
- package/lib/cli/bomAssembly.js +172 -4
- package/lib/cli/cliOptions.js +121 -17
- package/lib/cli/index.js +720 -902
- package/lib/cli/jsBom.js +156 -64
- package/lib/cli/jvmBom.js +602 -86
- package/lib/cli/managedBom.js +161 -19
- package/lib/cli/nativeBom.js +52 -5
- package/lib/core/boundedFile.js +344 -0
- package/lib/core/brotliProbe.js +182 -0
- package/lib/core/env.js +34 -0
- package/lib/core/fs.js +138 -3
- package/lib/core/globPatterns.js +218 -0
- package/lib/core/httpClient.js +98 -1
- package/lib/core/lockPaths.js +38 -0
- package/lib/core/paths.js +24 -1
- package/lib/core/processTree.js +100 -8
- package/lib/core/projectConfig.js +332 -25
- package/lib/core/toolRegistry.js +184 -0
- package/lib/ecosystems/cppEvidence.js +263 -106
- package/lib/ecosystems/cppIncludeResolver.js +16 -5
- package/lib/ecosystems/denoutils.js +2 -2
- package/lib/ecosystems/ecosystems.js +25 -10
- package/lib/ecosystems/gemHostProbe.js +301 -0
- package/lib/ecosystems/golem.js +3 -8
- package/lib/ecosystems/gradleutils.js +1909 -229
- package/lib/ecosystems/jsEvidence.js +90 -38
- package/lib/ecosystems/kosi.js +3 -5
- package/lib/ecosystems/npmVersionResolution.js +376 -0
- package/lib/ecosystems/parsers-bazel.js +107 -6
- package/lib/ecosystems/parsers-js.js +505 -22
- package/lib/ecosystems/parsers-misc.js +209 -20
- package/lib/ecosystems/parsers-python.js +178 -30
- package/lib/ecosystems/parsers-rust.js +117 -15
- package/lib/ecosystems/pythonutils.js +128 -2
- package/lib/ecosystems/remote/huggingface.js +22 -0
- package/lib/ecosystems/rubyutils.js +538 -31
- package/lib/ecosystems/rusi.js +2 -4
- package/lib/ecosystems/scalacliutils.js +2 -0
- package/lib/ecosystems/scalasem.js +798 -152
- package/lib/ecosystems/vendoredCode.js +237 -3
- package/lib/ecosystems/venvProbe.js +360 -0
- package/lib/evinser/evinser.js +536 -71
- package/lib/evinser/scalasem.js +5 -1
- package/lib/helpers/agenticToolutils.js +525 -94
- package/lib/helpers/bomSigner.js +43 -9
- package/lib/helpers/jssSigner.js +1276 -0
- package/lib/helpers/vsixutils.js +1574 -315
- package/lib/inventory/agentBlueprint.js +193 -0
- package/lib/inventory/agentToolNames.js +145 -0
- package/lib/inventory/aiCollector.js +153 -7
- package/lib/inventory/aiInventory.js +44 -8
- package/lib/inventory/aiProviders.js +324 -0
- package/lib/inventory/atomUtils.js +77 -0
- package/lib/inventory/bomUtils.js +8 -1
- package/lib/inventory/brotliDecoder.js +142 -0
- package/lib/inventory/buildToolRateLimit.js +1 -1
- package/lib/inventory/cbomutils.js +56 -7
- package/lib/inventory/ciParsers/githubActionsLock.js +821 -0
- package/lib/inventory/citations.js +31 -2
- package/lib/inventory/communityAiConfigParser.js +978 -80
- package/lib/inventory/cyclonedx20.js +152 -0
- package/lib/inventory/cyclonedx20Common.js +286 -0
- package/lib/inventory/cyclonedx20Derived.js +159 -0
- package/lib/inventory/cyclonedx20Parties.js +552 -0
- package/lib/inventory/cyclonedx20Read.js +768 -0
- package/lib/inventory/cyclonedx20ReadCommon.js +374 -0
- package/lib/inventory/cyclonedx20ReadComponents.js +692 -0
- package/lib/inventory/cyclonedx20ReadContext.js +380 -0
- package/lib/inventory/cyclonedx20ReadEvidence.js +466 -0
- package/lib/inventory/cyclonedx20ReadSections.js +599 -0
- package/lib/inventory/cyclonedx20Render.js +766 -0
- package/lib/inventory/cyclonedx20RenderComponents.js +716 -0
- package/lib/inventory/cyclonedx20RenderDefinitions.js +405 -0
- package/lib/inventory/cyclonedx20RenderEvidence.js +726 -0
- package/lib/inventory/cyclonedx20RenderHardware.js +203 -0
- package/lib/inventory/cyclonedx20RenderPatents.js +174 -0
- package/lib/inventory/cyclonedx20RenderRefIds.js +314 -0
- package/lib/inventory/cyclonedx20RenderSections.js +499 -0
- package/lib/inventory/cyclonedx20Tables.js +594 -0
- package/lib/inventory/deps.js +141 -13
- package/lib/inventory/dosai.js +375 -6
- package/lib/inventory/dosaiParsers.js +3 -6
- package/lib/inventory/dotnetRuntime.js +367 -0
- package/lib/inventory/ecosystemFormulationParsers.js +979 -0
- package/lib/inventory/envcontext.js +436 -48
- package/lib/inventory/evidenceUtils.js +13 -1
- package/lib/inventory/fetchBatch.js +1 -1
- package/lib/inventory/formulationParsers.js +124 -14
- package/lib/inventory/gtfobins.js +13 -0
- package/lib/inventory/hbom.js +45 -6
- package/lib/inventory/hbomLoader.js +166 -0
- package/lib/inventory/hostRuntimeProbe.js +686 -0
- package/lib/inventory/jvmLocalRepos.js +9 -2
- package/lib/inventory/jvmToolEnv.js +29 -0
- package/lib/inventory/licenseEnhancer.js +12 -0
- package/lib/inventory/mavenCentralMirror.js +534 -0
- package/lib/inventory/mcpConfigParser.js +5 -0
- package/lib/inventory/nodeBuildInfo.js +218 -0
- package/lib/inventory/nodeHostProbe.js +202 -0
- package/lib/inventory/occurrenceKey.js +90 -0
- package/lib/inventory/osPackageResolver.js +182 -0
- package/lib/inventory/phpBuildInfo.js +10 -59
- package/lib/inventory/phpHostProbe.js +32 -488
- package/lib/inventory/pqcMigration.js +426 -0
- package/lib/inventory/rubyBuildInfo.js +972 -0
- package/lib/inventory/rubyHostProbe.js +218 -0
- package/lib/inventory/rustFormulationParser.js +21 -10
- package/lib/inventory/scalaCoords.js +4 -3
- package/lib/inventory/scalaDedupe.js +440 -0
- package/lib/inventory/source.js +114 -8
- package/lib/managers/binary.js +337 -3
- package/lib/managers/docker.js +79 -0
- package/lib/parsers/huggingfaceManifest.js +9 -1
- package/lib/parsers/huggingfaceUtils.js +18 -0
- package/lib/parsers/kiroPermissions.js +166 -0
- package/lib/parsers/largeJson.js +28 -11
- package/lib/parsers/vscodeExtensionId.js +183 -0
- package/lib/server/server.js +48 -35
- package/lib/stages/postgen/postgen.js +41 -1
- package/lib/stages/postgen/ruleEngine.js +13 -5
- package/lib/stages/postgen/specVersionCompat.js +76 -0
- package/lib/stages/pregen/envAudit.js +1 -0
- package/lib/stages/pregen/pregen.js +114 -57
- package/lib/validator/bomValidator.js +14 -2
- package/lib/validator/complianceEngine.js +30 -3
- package/lib/validator/complianceRules.js +1416 -4
- package/lib/validator/generated/validate-1.6.mjs +1 -1
- package/lib/validator/generated/validate-1.7.mjs +1 -1
- package/lib/validator/generated/validate-2.0.mjs +57554 -13851
- package/lib/validator/index.js +49 -8
- package/lib/validator/reporters/json.js +6 -0
- package/package.json +11 -10
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +6 -2
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +29 -1
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +6 -0
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jsBom.d.ts +3 -18
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +15 -0
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/boundedFile.d.ts +100 -0
- package/types/lib/core/boundedFile.d.ts.map +1 -0
- package/types/lib/core/brotliProbe.d.ts +37 -0
- package/types/lib/core/brotliProbe.d.ts.map +1 -0
- package/types/lib/core/env.d.ts +14 -0
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts +4 -0
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/globPatterns.d.ts +70 -0
- package/types/lib/core/globPatterns.d.ts.map +1 -0
- package/types/lib/core/httpClient.d.ts +24 -0
- package/types/lib/core/httpClient.d.ts.map +1 -1
- package/types/lib/core/lockPaths.d.ts +19 -0
- package/types/lib/core/lockPaths.d.ts.map +1 -0
- package/types/lib/core/paths.d.ts +9 -0
- package/types/lib/core/paths.d.ts.map +1 -1
- package/types/lib/core/processTree.d.ts +17 -4
- package/types/lib/core/processTree.d.ts.map +1 -1
- package/types/lib/core/projectConfig.d.ts +47 -8
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/toolRegistry.d.ts +36 -0
- package/types/lib/core/toolRegistry.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +40 -13
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts +2 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/gemHostProbe.d.ts +28 -0
- package/types/lib/ecosystems/gemHostProbe.d.ts.map +1 -0
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +294 -20
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts +14 -1
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts.map +1 -1
- package/types/lib/ecosystems/npmVersionResolution.d.ts +119 -0
- package/types/lib/ecosystems/npmVersionResolution.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +17 -20
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +19 -0
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +10 -0
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +19 -1
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +144 -12
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalasem.d.ts +58 -16
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
- package/types/lib/ecosystems/vendoredCode.d.ts +26 -0
- package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -1
- package/types/lib/ecosystems/venvProbe.d.ts +40 -0
- package/types/lib/ecosystems/venvProbe.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +120 -13
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/scalasem.d.ts.map +1 -1
- package/types/lib/helpers/agenticToolutils.d.ts +53 -19
- package/types/lib/helpers/agenticToolutils.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +20 -3
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/helpers/jssSigner.d.ts +288 -0
- package/types/lib/helpers/jssSigner.d.ts.map +1 -0
- package/types/lib/helpers/vsixutils.d.ts +303 -19
- package/types/lib/helpers/vsixutils.d.ts.map +1 -1
- package/types/lib/inventory/agentBlueprint.d.ts +70 -0
- package/types/lib/inventory/agentBlueprint.d.ts.map +1 -0
- package/types/lib/inventory/agentToolNames.d.ts +51 -0
- package/types/lib/inventory/agentToolNames.d.ts.map +1 -0
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/aiInventory.d.ts.map +1 -1
- package/types/lib/inventory/aiProviders.d.ts +85 -0
- package/types/lib/inventory/aiProviders.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +19 -0
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/bomUtils.d.ts.map +1 -1
- package/types/lib/inventory/brotliDecoder.d.ts +58 -0
- package/types/lib/inventory/brotliDecoder.d.ts.map +1 -0
- package/types/lib/inventory/cbomutils.d.ts +17 -0
- package/types/lib/inventory/cbomutils.d.ts.map +1 -1
- package/types/lib/inventory/ciParsers/githubActionsLock.d.ts +101 -0
- package/types/lib/inventory/ciParsers/githubActionsLock.d.ts.map +1 -0
- package/types/lib/inventory/citations.d.ts +5 -0
- package/types/lib/inventory/citations.d.ts.map +1 -1
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/cyclonedx20.d.ts +99 -0
- package/types/lib/inventory/cyclonedx20.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Common.d.ts +102 -0
- package/types/lib/inventory/cyclonedx20Common.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Derived.d.ts +74 -0
- package/types/lib/inventory/cyclonedx20Derived.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Parties.d.ts +91 -0
- package/types/lib/inventory/cyclonedx20Parties.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Read.d.ts +51 -0
- package/types/lib/inventory/cyclonedx20Read.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadCommon.d.ts +69 -0
- package/types/lib/inventory/cyclonedx20ReadCommon.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadComponents.d.ts +77 -0
- package/types/lib/inventory/cyclonedx20ReadComponents.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadContext.d.ts +118 -0
- package/types/lib/inventory/cyclonedx20ReadContext.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts +40 -0
- package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadSections.d.ts +45 -0
- package/types/lib/inventory/cyclonedx20ReadSections.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Render.d.ts +53 -0
- package/types/lib/inventory/cyclonedx20Render.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderComponents.d.ts +73 -0
- package/types/lib/inventory/cyclonedx20RenderComponents.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts +29 -0
- package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts +110 -0
- package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderHardware.d.ts +42 -0
- package/types/lib/inventory/cyclonedx20RenderHardware.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderPatents.d.ts +26 -0
- package/types/lib/inventory/cyclonedx20RenderPatents.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts +55 -0
- package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderSections.d.ts +45 -0
- package/types/lib/inventory/cyclonedx20RenderSections.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Tables.d.ts +134 -0
- package/types/lib/inventory/cyclonedx20Tables.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +35 -2
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +36 -1
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
- package/types/lib/inventory/dotnetRuntime.d.ts +91 -0
- package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -0
- package/types/lib/inventory/ecosystemFormulationParsers.d.ts +73 -0
- package/types/lib/inventory/ecosystemFormulationParsers.d.ts.map +1 -0
- package/types/lib/inventory/envcontext.d.ts +74 -12
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
- package/types/lib/inventory/gtfobins.d.ts.map +1 -1
- package/types/lib/inventory/hbom.d.ts +11 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -1
- package/types/lib/inventory/hbomLoader.d.ts +54 -0
- package/types/lib/inventory/hbomLoader.d.ts.map +1 -1
- package/types/lib/inventory/hostRuntimeProbe.d.ts +44 -0
- package/types/lib/inventory/hostRuntimeProbe.d.ts.map +1 -0
- package/types/lib/inventory/jvmLocalRepos.d.ts +5 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -1
- package/types/lib/inventory/jvmToolEnv.d.ts +12 -0
- package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
- package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -1
- package/types/lib/inventory/mavenCentralMirror.d.ts +170 -0
- package/types/lib/inventory/mavenCentralMirror.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/nodeBuildInfo.d.ts +95 -0
- package/types/lib/inventory/nodeBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/nodeHostProbe.d.ts +15 -0
- package/types/lib/inventory/nodeHostProbe.d.ts.map +1 -0
- package/types/lib/inventory/occurrenceKey.d.ts +52 -0
- package/types/lib/inventory/occurrenceKey.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +38 -0
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
- package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -1
- package/types/lib/inventory/phpHostProbe.d.ts.map +1 -1
- package/types/lib/inventory/pqcMigration.d.ts +84 -0
- package/types/lib/inventory/pqcMigration.d.ts.map +1 -0
- package/types/lib/inventory/rubyBuildInfo.d.ts +271 -0
- package/types/lib/inventory/rubyBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/rubyHostProbe.d.ts +47 -0
- package/types/lib/inventory/rubyHostProbe.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts +7 -2
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/scalaCoords.d.ts.map +1 -1
- package/types/lib/inventory/scalaDedupe.d.ts +43 -0
- package/types/lib/inventory/scalaDedupe.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +25 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +12 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/parsers/huggingfaceManifest.d.ts +10 -1
- package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -1
- package/types/lib/parsers/huggingfaceUtils.d.ts +12 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
- package/types/lib/parsers/kiroPermissions.d.ts +62 -0
- package/types/lib/parsers/kiroPermissions.d.ts.map +1 -0
- package/types/lib/parsers/largeJson.d.ts +4 -3
- package/types/lib/parsers/largeJson.d.ts.map +1 -1
- package/types/lib/parsers/vscodeExtensionId.d.ts +48 -0
- package/types/lib/parsers/vscodeExtensionId.d.ts.map +1 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +7 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts +25 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
- package/types/lib/stages/pregen/pregen.d.ts +12 -8
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts +5 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/complianceEngine.d.ts +4 -4
- package/types/lib/validator/complianceEngine.d.ts.map +1 -1
- package/types/lib/validator/complianceRules.d.ts +14 -2
- package/types/lib/validator/complianceRules.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +10 -0
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
package/lib/cli/jvmBom.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
2
|
import { readdirSync, readFileSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
4
|
+
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import process from "node:process";
|
|
6
6
|
|
|
7
7
|
import { build } from "@cdxgen/cdx-purl";
|
|
@@ -41,22 +41,34 @@ import {
|
|
|
41
41
|
} from "../core/projectTooling.js";
|
|
42
42
|
import { extractJarArchive, getMvnMetadata } from "../ecosystems/ecosystems.js";
|
|
43
43
|
import {
|
|
44
|
+
applyGradleVerificationMetadata,
|
|
44
45
|
buildGradleCommandArguments,
|
|
45
46
|
buildObjectForGradleModule,
|
|
46
47
|
collectGradleDependencies,
|
|
48
|
+
excludeGradleBuildTooling,
|
|
47
49
|
executeParallelGradleProperties,
|
|
50
|
+
findGradleLockfiles,
|
|
51
|
+
findGradleVerificationMetadata,
|
|
48
52
|
findMillDaemons,
|
|
49
53
|
getGradleCommand,
|
|
50
54
|
getMavenCommand,
|
|
51
55
|
getMillCommand,
|
|
52
56
|
getMillVersion,
|
|
57
|
+
gradleArgsFromEnv,
|
|
58
|
+
gradleDependencyTasks,
|
|
59
|
+
gradleVerificationMainArtifact,
|
|
53
60
|
hasGradleInvocationFailure,
|
|
54
61
|
isProjectToolingAllowed,
|
|
62
|
+
loadGradleModulesForReports,
|
|
55
63
|
parseGradleDep,
|
|
56
64
|
parseGradleInfoLogsForUrls,
|
|
65
|
+
parseGradleLockfiles,
|
|
57
66
|
parseGradleProperties,
|
|
58
67
|
parseGradleResolvedDistributions,
|
|
68
|
+
parseGradleVerificationMetadata,
|
|
59
69
|
parseGradleVersionCatalog,
|
|
70
|
+
readGradleRootProjectName,
|
|
71
|
+
reconcileGradleComponents,
|
|
60
72
|
recordGradleInvocationFailure,
|
|
61
73
|
splitOutputByGradleProjects,
|
|
62
74
|
stopMillDaemons,
|
|
@@ -91,6 +103,7 @@ import {
|
|
|
91
103
|
} from "../ecosystems/sbtutils.js";
|
|
92
104
|
import { collectScalaCliComponents } from "../ecosystems/scalacliutils.js";
|
|
93
105
|
import { collectScalaJsNpmComponents } from "../ecosystems/scalasem.js";
|
|
106
|
+
import { isInVendoredDir } from "../ecosystems/vendoredCode.js";
|
|
94
107
|
import {
|
|
95
108
|
isBuildToolRateLimited,
|
|
96
109
|
noteBuildToolRateLimit,
|
|
@@ -99,6 +112,7 @@ import {
|
|
|
99
112
|
collectJarNS,
|
|
100
113
|
collectMvnDependencies,
|
|
101
114
|
convertJarNSToPackages,
|
|
115
|
+
namespaceMappingOfComponents,
|
|
102
116
|
} from "../inventory/deps.js";
|
|
103
117
|
import { mergeDependencies, trimComponents } from "../inventory/depsUtils.js";
|
|
104
118
|
import {
|
|
@@ -112,8 +126,20 @@ import {
|
|
|
112
126
|
projectSettingsArgs,
|
|
113
127
|
} from "../inventory/jvmLocalRepos.js";
|
|
114
128
|
import { readGradleWrapperVersion } from "../inventory/jvmToolEnv.js";
|
|
115
|
-
import {
|
|
129
|
+
import {
|
|
130
|
+
bazelMirrorArgs,
|
|
131
|
+
coursierMirrorEnv,
|
|
132
|
+
gradleMirrorInitScriptArgs,
|
|
133
|
+
mavenMirrorSettingsArgs,
|
|
134
|
+
mavenWrapperMirrorEnv,
|
|
135
|
+
sbtMirrorEnv,
|
|
136
|
+
} from "../inventory/mavenCentralMirror.js";
|
|
137
|
+
import { applyPurl, mavenPurl, tryBuildPurl } from "../inventory/purl.js";
|
|
116
138
|
import { publishedArtifactId } from "../inventory/scalaCoords.js";
|
|
139
|
+
import {
|
|
140
|
+
mergeScalaDuplicateComponents,
|
|
141
|
+
rekeyNamespaceMapping,
|
|
142
|
+
} from "../inventory/scalaDedupe.js";
|
|
117
143
|
import {
|
|
118
144
|
buildBomNSData,
|
|
119
145
|
createDefaultParentComponent,
|
|
@@ -253,6 +279,67 @@ export async function collectSbtDependencyJars(pkgList, known = {}) {
|
|
|
253
279
|
return nsMapping;
|
|
254
280
|
}
|
|
255
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Keep apart two independent Maven projects that declare the same
|
|
284
|
+
* coordinates, such as sample projects in `one/` and `two/` that both call
|
|
285
|
+
* themselves `com.example:demo:0.0.1-SNAPSHOT`. When `component` has the
|
|
286
|
+
* bom-ref of the parent or of a module already collected but comes from a
|
|
287
|
+
* different pom.xml, it gets the directory of its pom, relative to the scan
|
|
288
|
+
* root, as the purl subpath, and the dependency entries that name it follow.
|
|
289
|
+
*
|
|
290
|
+
* @param {Object} component Root component of a Maven tree, updated in place
|
|
291
|
+
* @param {Object} parentComponent Parent component and the modules under it
|
|
292
|
+
* @param {string} rootPath Directory being scanned
|
|
293
|
+
* @param {Object[]} dependenciesList Dependency entries of the tree, updated in place
|
|
294
|
+
* @returns {boolean} True when the component got a distinct identity
|
|
295
|
+
*/
|
|
296
|
+
export function separateDuplicateMavenProject(
|
|
297
|
+
component,
|
|
298
|
+
parentComponent,
|
|
299
|
+
rootPath,
|
|
300
|
+
dependenciesList = [],
|
|
301
|
+
) {
|
|
302
|
+
const ref = component?.["bom-ref"];
|
|
303
|
+
if (!ref || !component.purl) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
const holder = [parentComponent, ...(parentComponent?.components || [])].find(
|
|
307
|
+
(candidate) => candidate?.["bom-ref"] === ref,
|
|
308
|
+
);
|
|
309
|
+
const srcFile = (c) =>
|
|
310
|
+
c?.properties?.find((p) => p.name === "internal:SrcFile")?.value;
|
|
311
|
+
const ownPom = srcFile(component);
|
|
312
|
+
const holderPom = srcFile(holder);
|
|
313
|
+
if (!ownPom || !holderPom || resolve(ownPom) === resolve(holderPom)) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
const subpath = relative(resolve(rootPath), dirname(resolve(ownPom)))
|
|
317
|
+
.split(sep)
|
|
318
|
+
.filter((segment) => segment && segment !== "..")
|
|
319
|
+
.join("/");
|
|
320
|
+
const purl =
|
|
321
|
+
subpath &&
|
|
322
|
+
tryBuildPurl({
|
|
323
|
+
type: "maven",
|
|
324
|
+
namespace: component.group || null,
|
|
325
|
+
name: component.name,
|
|
326
|
+
version: component.version || null,
|
|
327
|
+
qualifiers: component.qualifiers || { type: "jar" },
|
|
328
|
+
subpath,
|
|
329
|
+
});
|
|
330
|
+
if (!purl) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
applyPurl(component, purl);
|
|
334
|
+
const newRef = component["bom-ref"];
|
|
335
|
+
for (const entry of dependenciesList) {
|
|
336
|
+
if (entry.ref === ref) {
|
|
337
|
+
entry.ref = newRef;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
|
|
256
343
|
/**
|
|
257
344
|
* The purls and bom-refs of a parent component and the module components
|
|
258
345
|
* nested under it.
|
|
@@ -565,6 +652,33 @@ export async function createJavaBom(path, options) {
|
|
|
565
652
|
let jarNSMapping = {};
|
|
566
653
|
let pkgList = [];
|
|
567
654
|
let dependencies = [];
|
|
655
|
+
// The committed gradle/verification-metadata.xml of this build, if any,
|
|
656
|
+
// and the metadata parsed from it exactly once. These live at function
|
|
657
|
+
// scope because the fallback runs inside the Gradle block below while the
|
|
658
|
+
// enrichment runs after getMvnMetadata, outside the try that guards the
|
|
659
|
+
// per-tool sections, so a deferred failure keeps the enrichment too.
|
|
660
|
+
let gradleVerificationFile;
|
|
661
|
+
let gradleVerificationRootDir;
|
|
662
|
+
let gradleVerificationData;
|
|
663
|
+
let gradleVerificationParsed = false;
|
|
664
|
+
const gradleVerification = () => {
|
|
665
|
+
if (!gradleVerificationParsed) {
|
|
666
|
+
gradleVerificationParsed = true;
|
|
667
|
+
if (gradleVerificationFile) {
|
|
668
|
+
gradleVerificationData = parseGradleVerificationMetadata(
|
|
669
|
+
gradleVerificationFile,
|
|
670
|
+
{ rootDir: gradleVerificationRootDir },
|
|
671
|
+
);
|
|
672
|
+
if (gradleVerificationData) {
|
|
673
|
+
const { configuration } = gradleVerificationData;
|
|
674
|
+
thoughtLog(
|
|
675
|
+
`${gradleVerificationFile} records ${configuration.trustedKeyCount} trusted key(s), ${configuration.trustedArtifactRuleCount} trust rule(s), ${configuration.ignoredKeyCount} ignored key(s) and ${configuration.keyServerCount} key server(s).`,
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return gradleVerificationData;
|
|
681
|
+
};
|
|
568
682
|
// cyclone-dx-maven plugin creates a component for the app under metadata
|
|
569
683
|
// This is subsequently referred to in the dependencies list
|
|
570
684
|
let parentComponent = {};
|
|
@@ -814,6 +928,17 @@ export async function createJavaBom(path, options) {
|
|
|
814
928
|
const projectSettings = projectSettingsArgs(basePath, {
|
|
815
929
|
secureMode: isSecureModeActive(),
|
|
816
930
|
});
|
|
931
|
+
// When the mirror switch is on, Maven resolves Central from the
|
|
932
|
+
// mirror through a generated global settings file; a project
|
|
933
|
+
// settings.xml is merged into that copy so its repositories and its
|
|
934
|
+
// own mirror survive. A settings file the user named keeps winning.
|
|
935
|
+
const mirrorSettingsArgs = mavenMirrorSettingsArgs(
|
|
936
|
+
projectSettings.settingsFile,
|
|
937
|
+
);
|
|
938
|
+
const mvnSettingsArgs = mirrorSettingsArgs.length
|
|
939
|
+
? mirrorSettingsArgs
|
|
940
|
+
: projectSettings.args;
|
|
941
|
+
const mvnSpawnEnv = { ...process.env, ...mavenWrapperMirrorEnv() };
|
|
817
942
|
if (projectSettings.args.length) {
|
|
818
943
|
console.log(
|
|
819
944
|
`Passing ${projectSettings.settingsFile} to Maven as global settings (-gs), so your own settings.xml still applies. Name a settings file in MVN_ARGS to change this.`,
|
|
@@ -839,9 +964,10 @@ export async function createJavaBom(path, options) {
|
|
|
839
964
|
if (!useMavenDepsTree && !isBuildToolRateLimited("maven")) {
|
|
840
965
|
thoughtLog("The user wants me to use the cyclonedx-maven plugin.");
|
|
841
966
|
console.log(`Executing '${mavenCmd}' in`, basePath);
|
|
842
|
-
result = safeSpawnSync(mavenCmd, mvnArgs, {
|
|
967
|
+
result = safeSpawnSync(mavenCmd, mvnArgs.concat(mirrorSettingsArgs), {
|
|
843
968
|
cwd: basePath,
|
|
844
969
|
shell: isWin,
|
|
970
|
+
env: mvnSpawnEnv,
|
|
845
971
|
});
|
|
846
972
|
noteBuildToolRateLimit("maven", commandOutputText(result), {
|
|
847
973
|
command: `${basename(mavenCmd)} ${mvnArgs.join(" ")}`,
|
|
@@ -906,7 +1032,7 @@ export async function createJavaBom(path, options) {
|
|
|
906
1032
|
addArgs = parseMavenArgs(readEnvironmentVariable("MVN_ARGS"));
|
|
907
1033
|
mvnTreeArgs = mvnTreeArgs.concat(addArgs);
|
|
908
1034
|
}
|
|
909
|
-
mvnTreeArgs = mvnTreeArgs.concat(
|
|
1035
|
+
mvnTreeArgs = mvnTreeArgs.concat(mvnSettingsArgs);
|
|
910
1036
|
// For the first pom alone, we need to execute first in non-recursive mode to capture
|
|
911
1037
|
// the parent component. Then, we execute all of them in recursive mode
|
|
912
1038
|
// A rate limit the --deep copy-dependencies run met ends it too.
|
|
@@ -922,11 +1048,12 @@ export async function createJavaBom(path, options) {
|
|
|
922
1048
|
];
|
|
923
1049
|
findParentComponentArgs = findParentComponentArgs.concat(
|
|
924
1050
|
addArgs,
|
|
925
|
-
|
|
1051
|
+
mvnSettingsArgs,
|
|
926
1052
|
);
|
|
927
1053
|
result = safeSpawnSync(mavenCmd, findParentComponentArgs, {
|
|
928
1054
|
cwd: basePath,
|
|
929
1055
|
shell: isWin,
|
|
1056
|
+
env: mvnSpawnEnv,
|
|
930
1057
|
});
|
|
931
1058
|
noteBuildToolRateLimit("maven", commandOutputText(result), {
|
|
932
1059
|
command: `${basename(mavenCmd)} ${findParentComponentArgs.join(" ")}`,
|
|
@@ -956,10 +1083,11 @@ export async function createJavaBom(path, options) {
|
|
|
956
1083
|
"dependency:tree",
|
|
957
1084
|
"-N",
|
|
958
1085
|
`-DoutputFile=${tempMvnParentTreeText}`,
|
|
959
|
-
].concat(addArgs,
|
|
1086
|
+
].concat(addArgs, mvnSettingsArgs);
|
|
960
1087
|
result = safeSpawnSync(mavenCmd, findParentComponentArgs, {
|
|
961
1088
|
cwd: basePath,
|
|
962
1089
|
shell: isWin,
|
|
1090
|
+
env: mvnSpawnEnv,
|
|
963
1091
|
});
|
|
964
1092
|
}
|
|
965
1093
|
if (result.status === 0) {
|
|
@@ -1004,6 +1132,7 @@ export async function createJavaBom(path, options) {
|
|
|
1004
1132
|
result = safeSpawnSync(mavenCmd, mvnTreeArgs, {
|
|
1005
1133
|
cwd: basePath,
|
|
1006
1134
|
shell: isWin,
|
|
1135
|
+
env: mvnSpawnEnv,
|
|
1007
1136
|
});
|
|
1008
1137
|
noteBuildToolRateLimit("maven", commandOutputText(result), {
|
|
1009
1138
|
command: `${basename(mavenCmd)} ${mvnTreeArgs.join(" ")}`,
|
|
@@ -1029,10 +1158,11 @@ export async function createJavaBom(path, options) {
|
|
|
1029
1158
|
mvnTreeArgs = [
|
|
1030
1159
|
"dependency:tree",
|
|
1031
1160
|
`-DoutputFile=${tempMvnTreeText}`,
|
|
1032
|
-
].concat(addArgs,
|
|
1161
|
+
].concat(addArgs, mvnSettingsArgs);
|
|
1033
1162
|
result = safeSpawnSync(mavenCmd, mvnTreeArgs, {
|
|
1034
1163
|
cwd: basePath,
|
|
1035
1164
|
shell: isWin,
|
|
1165
|
+
env: mvnSpawnEnv,
|
|
1036
1166
|
});
|
|
1037
1167
|
noteBuildToolRateLimit("maven", commandOutputText(result), {
|
|
1038
1168
|
command: `${basename(mavenCmd)} ${mvnTreeArgs.join(" ")}`,
|
|
@@ -1182,6 +1312,12 @@ export async function createJavaBom(path, options) {
|
|
|
1182
1312
|
parentComponent = tmpParentComponent;
|
|
1183
1313
|
parentComponent.components = [];
|
|
1184
1314
|
} else {
|
|
1315
|
+
separateDuplicateMavenProject(
|
|
1316
|
+
tmpParentComponent,
|
|
1317
|
+
parentComponent,
|
|
1318
|
+
path,
|
|
1319
|
+
parsedList.dependenciesList,
|
|
1320
|
+
);
|
|
1185
1321
|
parentComponent.components.push(tmpParentComponent);
|
|
1186
1322
|
}
|
|
1187
1323
|
if (parsedList?.dependenciesList?.length) {
|
|
@@ -1309,9 +1445,14 @@ export async function createJavaBom(path, options) {
|
|
|
1309
1445
|
}
|
|
1310
1446
|
}
|
|
1311
1447
|
const allProjects = [];
|
|
1312
|
-
|
|
1448
|
+
// Modules keyed by bom-ref: a module without a purl still has a bom-ref
|
|
1449
|
+
// of its own, while every such module shares an undefined purl.
|
|
1450
|
+
const allProjectsAddedRefs = new Map();
|
|
1313
1451
|
const rootDependsOn = new Set();
|
|
1314
1452
|
const gradleModules = new Map();
|
|
1453
|
+
// Included builds that build Gradle plugins, such as a build-logic build
|
|
1454
|
+
// included from pluginManagement. Their classpath is build tooling.
|
|
1455
|
+
const gradlePluginBuilds = new Set();
|
|
1315
1456
|
// Determine the root path for gradle
|
|
1316
1457
|
// Fixes gradle invocation for microservices-demo
|
|
1317
1458
|
let gradleRootPath = path;
|
|
@@ -1329,15 +1470,51 @@ export async function createJavaBom(path, options) {
|
|
|
1329
1470
|
"Hmm, there is a gradle.properties file. Do we need any private modules or custom JVM arguments for this project 🤔?",
|
|
1330
1471
|
);
|
|
1331
1472
|
}
|
|
1332
|
-
//
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1473
|
+
// The package-manager gate the Gradle invocations below share: a scan
|
|
1474
|
+
// that prefers another JVM build tool over Gradle reads no Gradle
|
|
1475
|
+
// lockfiles either.
|
|
1476
|
+
const gradleManagerAllowed = isPackageManagerAllowed(
|
|
1477
|
+
"gradle",
|
|
1478
|
+
["maven", "bazel", "sbt", "mill"],
|
|
1479
|
+
options,
|
|
1480
|
+
);
|
|
1481
|
+
// The committed Gradle dependency lockfiles record the resolved versions
|
|
1482
|
+
// of every locked configuration, so they are an inventory source that
|
|
1483
|
+
// needs no Gradle run. They are looked for only in a Gradle build: a
|
|
1484
|
+
// Maven-rooted scan does not pick up a nested sample's lockfile.
|
|
1485
|
+
const gradleLockFiles =
|
|
1486
|
+
gradleFiles?.length && gradleManagerAllowed
|
|
1487
|
+
? findGradleLockfiles(gradleRootPath, options)
|
|
1488
|
+
: [];
|
|
1489
|
+
// The committed gradle/verification-metadata.xml records the checksums
|
|
1490
|
+
// and PGP key ids Gradle verified when `gradle
|
|
1491
|
+
// --write-verification-metadata` last ran. Like the lockfiles, it is an
|
|
1492
|
+
// inventory source that needs no Gradle run, and it is looked for only in
|
|
1493
|
+
// a Gradle build.
|
|
1494
|
+
gradleVerificationFile =
|
|
1495
|
+
gradleFiles?.length && gradleManagerAllowed
|
|
1496
|
+
? findGradleVerificationMetadata(gradleRootPath)
|
|
1497
|
+
: undefined;
|
|
1498
|
+
gradleVerificationRootDir = gradleRootPath;
|
|
1499
|
+
// `gradle properties` evaluates the project's build scripts and `gradle
|
|
1500
|
+
// dependencies` resolves the graph, so both belong to the
|
|
1501
|
+
// dependency-tooling surface. The properties task runs whenever
|
|
1502
|
+
// `isProjectToolingAllowed` lets it, as it names the root project and
|
|
1503
|
+
// the subprojects; only the gradle-prefer-lockfile preference holds it
|
|
1504
|
+
// back. The dependencies task also needs `options.installDeps`. When
|
|
1505
|
+
// either check would stop the dependencies task, or when the preference
|
|
1506
|
+
// asks for it, the lockfiles supply the components instead.
|
|
1507
|
+
const gradleToolingAllowed = isProjectToolingAllowed(options);
|
|
1508
|
+
const gradlePreferLockfile = isFeatureEnabled(
|
|
1509
|
+
options,
|
|
1510
|
+
"gradle-prefer-lockfile",
|
|
1511
|
+
);
|
|
1512
|
+
const gradleSkipProperties =
|
|
1513
|
+
gradlePreferLockfile && gradleLockFiles.length > 0;
|
|
1514
|
+
const gradleUseLockfiles =
|
|
1515
|
+
gradleLockFiles.length > 0 &&
|
|
1516
|
+
(gradlePreferLockfile || !gradleToolingAllowed || !options.installDeps);
|
|
1517
|
+
if (gradleFiles?.length && gradleManagerAllowed) {
|
|
1341
1518
|
const wrapperInfo = readGradleWrapperVersion(gradleRootPath);
|
|
1342
1519
|
if (wrapperInfo) {
|
|
1343
1520
|
try {
|
|
@@ -1399,6 +1576,177 @@ export async function createJavaBom(path, options) {
|
|
|
1399
1576
|
// ignore
|
|
1400
1577
|
}
|
|
1401
1578
|
}
|
|
1579
|
+
}
|
|
1580
|
+
// A module of this build that another one consumes by its coordinates is
|
|
1581
|
+
// a project, not a dependency, so the fallback sources below drop it.
|
|
1582
|
+
const dropGradleModuleComponents = (pkgs) => {
|
|
1583
|
+
const moduleRefs = new Set(
|
|
1584
|
+
[parentComponent, ...(parentComponent?.components || [])]
|
|
1585
|
+
.map((c) => c?.["bom-ref"])
|
|
1586
|
+
.filter(Boolean),
|
|
1587
|
+
);
|
|
1588
|
+
return pkgs.filter((pkg) => !moduleRefs.has(pkg["bom-ref"]));
|
|
1589
|
+
};
|
|
1590
|
+
// Without `gradle properties` nothing named the root project. The
|
|
1591
|
+
// settings script names it, and the directory name stands in when it
|
|
1592
|
+
// does not, so the BOM still has a primary component.
|
|
1593
|
+
const ensureGradleParentComponent = () => {
|
|
1594
|
+
if (!parentComponent || !Object.keys(parentComponent).length) {
|
|
1595
|
+
const rootProjectName = readGradleRootProjectName(gradleRootPath);
|
|
1596
|
+
parentComponent = createDefaultParentComponent(
|
|
1597
|
+
gradleRootPath,
|
|
1598
|
+
"maven",
|
|
1599
|
+
rootProjectName && !("project-name" in options)
|
|
1600
|
+
? {
|
|
1601
|
+
...options,
|
|
1602
|
+
"project-name": rootProjectName,
|
|
1603
|
+
projectName: rootProjectName,
|
|
1604
|
+
}
|
|
1605
|
+
: options,
|
|
1606
|
+
);
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
// The lockfiles stand in for the Gradle dependency resolution this scan
|
|
1610
|
+
// is not making, prefers not to make, or that produced nothing. They
|
|
1611
|
+
// record resolved versions but no graph, so the components carry no
|
|
1612
|
+
// dependency edges and the scan records what that costs. Returns the
|
|
1613
|
+
// number of components added.
|
|
1614
|
+
const addGradleLockfileComponents = () => {
|
|
1615
|
+
const lockfilePkgs = dropGradleModuleComponents(
|
|
1616
|
+
parseGradleLockfiles(gradleLockFiles, {
|
|
1617
|
+
rootDir: gradleRootPath,
|
|
1618
|
+
}),
|
|
1619
|
+
);
|
|
1620
|
+
if (!lockfilePkgs.length) {
|
|
1621
|
+
return 0;
|
|
1622
|
+
}
|
|
1623
|
+
pkgList = pkgList.concat(lockfilePkgs);
|
|
1624
|
+
recordDegradation("jvm.gradle.lockfile-only", {
|
|
1625
|
+
ecosystem: "java",
|
|
1626
|
+
tool: "gradle",
|
|
1627
|
+
impact: "transitive-deps",
|
|
1628
|
+
detail:
|
|
1629
|
+
"The components came from Gradle dependency lockfiles, which record no dependency graph between them.",
|
|
1630
|
+
});
|
|
1631
|
+
ensureGradleParentComponent();
|
|
1632
|
+
return lockfilePkgs.length;
|
|
1633
|
+
};
|
|
1634
|
+
// The version catalog and, on request, the verification file declare
|
|
1635
|
+
// coordinates without resolving them, so both are used only when Gradle
|
|
1636
|
+
// and the lockfiles produced no dependency information at all. The call
|
|
1637
|
+
// inside the Gradle run block happens before its failure paths, so a
|
|
1638
|
+
// build whose static sources resolved it is not degraded twice and not
|
|
1639
|
+
// failed with --fail-on-error over a BOM that has components. The
|
|
1640
|
+
// verification fallback stays off unless the
|
|
1641
|
+
// gradle-verification-fallback feature flag asks for it: the file
|
|
1642
|
+
// records what the build resolved when --write-verification-metadata
|
|
1643
|
+
// ran, which may be stale, and its components can only be optional.
|
|
1644
|
+
// Both belong to a Gradle build, so a scan without Gradle build files,
|
|
1645
|
+
// or one that prefers another JVM build tool, reads neither.
|
|
1646
|
+
const addGradleStaticFallbackComponents = () => {
|
|
1647
|
+
if (!gradleFiles?.length || !gradleManagerAllowed || pkgList.length) {
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
const catalogFiles = getAllFiles(
|
|
1651
|
+
path,
|
|
1652
|
+
`${options.multiProject ? "**/" : ""}gradle/libs.versions.toml`,
|
|
1653
|
+
options,
|
|
1654
|
+
);
|
|
1655
|
+
for (const catalogFile of catalogFiles) {
|
|
1656
|
+
if (DEBUG_MODE) {
|
|
1657
|
+
console.log(`Parsing ${catalogFile}`);
|
|
1658
|
+
}
|
|
1659
|
+
const dlist = parseGradleVersionCatalog(catalogFile);
|
|
1660
|
+
if (dlist?.length) {
|
|
1661
|
+
pkgList = pkgList.concat(dlist);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
if (
|
|
1665
|
+
pkgList.length ||
|
|
1666
|
+
!gradleVerificationFile ||
|
|
1667
|
+
!isFeatureEnabled(options, "gradle-verification-fallback")
|
|
1668
|
+
) {
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
const verificationMetadata = gradleVerification();
|
|
1672
|
+
if (!verificationMetadata) {
|
|
1673
|
+
return;
|
|
1674
|
+
}
|
|
1675
|
+
const verificationPkgs = [];
|
|
1676
|
+
for (const component of verificationMetadata.components.values()) {
|
|
1677
|
+
// A Gradle plugin marker coordinate publishes only a POM that
|
|
1678
|
+
// points at the real plugin, so it is not a dependency of the
|
|
1679
|
+
// build, and a coordinate without a main artifact is a parent or a
|
|
1680
|
+
// BOM rather than a component of this BOM.
|
|
1681
|
+
if (component.name.endsWith(".gradle.plugin")) {
|
|
1682
|
+
continue;
|
|
1683
|
+
}
|
|
1684
|
+
if (!gradleVerificationMainArtifact(component, false)) {
|
|
1685
|
+
continue;
|
|
1686
|
+
}
|
|
1687
|
+
const purl = mavenPurl(
|
|
1688
|
+
component.group,
|
|
1689
|
+
component.name,
|
|
1690
|
+
component.version,
|
|
1691
|
+
{
|
|
1692
|
+
type: "jar",
|
|
1693
|
+
},
|
|
1694
|
+
);
|
|
1695
|
+
if (!purl) {
|
|
1696
|
+
continue;
|
|
1697
|
+
}
|
|
1698
|
+
verificationPkgs.push({
|
|
1699
|
+
group: component.group,
|
|
1700
|
+
name: component.name,
|
|
1701
|
+
version: component.version,
|
|
1702
|
+
qualifiers: { type: "jar" },
|
|
1703
|
+
type: "library",
|
|
1704
|
+
// A component with no scope counts as required, and the file
|
|
1705
|
+
// cannot tell a runtime dependency from build tooling, so the
|
|
1706
|
+
// components are optional.
|
|
1707
|
+
scope: "optional",
|
|
1708
|
+
purl,
|
|
1709
|
+
"bom-ref": decodeURIComponent(purl),
|
|
1710
|
+
// The digests are merged in at the end of the scan, from the file
|
|
1711
|
+
// or from the artifact itself when the local cache holds it.
|
|
1712
|
+
properties: [
|
|
1713
|
+
{ name: "internal:SrcFile", value: gradleVerificationFile },
|
|
1714
|
+
{ name: "cdx:gradle:verificationMetadata", value: "true" },
|
|
1715
|
+
],
|
|
1716
|
+
evidence: {
|
|
1717
|
+
identity: {
|
|
1718
|
+
field: "purl",
|
|
1719
|
+
confidence: 1,
|
|
1720
|
+
concludedValue: purl,
|
|
1721
|
+
methods: [
|
|
1722
|
+
{
|
|
1723
|
+
technique: "manifest-analysis",
|
|
1724
|
+
confidence: 1,
|
|
1725
|
+
value: gradleVerificationFile,
|
|
1726
|
+
},
|
|
1727
|
+
],
|
|
1728
|
+
},
|
|
1729
|
+
},
|
|
1730
|
+
});
|
|
1731
|
+
}
|
|
1732
|
+
const addedPkgs = dropGradleModuleComponents(verificationPkgs);
|
|
1733
|
+
if (addedPkgs.length) {
|
|
1734
|
+
pkgList = pkgList.concat(addedPkgs);
|
|
1735
|
+
recordDegradation("jvm.gradle.verification-metadata-only", {
|
|
1736
|
+
ecosystem: "java",
|
|
1737
|
+
tool: "gradle",
|
|
1738
|
+
impact: "transitive-deps",
|
|
1739
|
+
detail:
|
|
1740
|
+
"The components came from gradle/verification-metadata.xml, which records no dependency graph between them.",
|
|
1741
|
+
});
|
|
1742
|
+
ensureGradleParentComponent();
|
|
1743
|
+
thoughtLog(
|
|
1744
|
+
`Obtained ${addedPkgs.length} components from ${gradleVerificationFile}. It says nothing about which module depends on which, and nothing about scopes.`,
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1747
|
+
};
|
|
1748
|
+
// Execute gradle properties
|
|
1749
|
+
if (gradleFiles?.length && gradleManagerAllowed && !gradleSkipProperties) {
|
|
1402
1750
|
let includedBuilds = [];
|
|
1403
1751
|
let allProjectsStr = [];
|
|
1404
1752
|
if (readEnvironmentVariable("GRADLE_INCLUDED_BUILDS")) {
|
|
@@ -1413,13 +1761,15 @@ export async function createJavaBom(path, options) {
|
|
|
1413
1761
|
const gradleInitArgs = readEnvironmentVariable("GRADLE_INCLUDED_BUILDS")
|
|
1414
1762
|
? []
|
|
1415
1763
|
: ["--init-script", GRADLE_INIT_SCRIPT];
|
|
1764
|
+
// The mirror init script joins cdxgen's own helper script; Gradle
|
|
1765
|
+
// applies every init script it is given.
|
|
1766
|
+
const gradleMirrorArgs = gradleMirrorInitScriptArgs();
|
|
1767
|
+
if (gradleMirrorArgs.length) {
|
|
1768
|
+
gradleInitArgs.push(...gradleMirrorArgs);
|
|
1769
|
+
}
|
|
1416
1770
|
if (resolveGradleDistribution && gradleInitArgs.length) {
|
|
1417
1771
|
gradleInitArgs.push("-PcdxgenResolveDistribution=true");
|
|
1418
1772
|
}
|
|
1419
|
-
// `gradle properties` evaluates the project's build scripts, so it is
|
|
1420
|
-
// part of the dependency-tooling surface gated by --no-install-deps
|
|
1421
|
-
// (and the pre-build lifecycle).
|
|
1422
|
-
const gradleToolingAllowed = isProjectToolingAllowed(options);
|
|
1423
1773
|
if (gradleToolingAllowed) {
|
|
1424
1774
|
parallelPropTaskOut = executeParallelGradleProperties(
|
|
1425
1775
|
gradleRootPath,
|
|
@@ -1484,12 +1834,19 @@ export async function createJavaBom(path, options) {
|
|
|
1484
1834
|
);
|
|
1485
1835
|
if (!includedBuilds.includes(key)) {
|
|
1486
1836
|
parentComponent = rootComponent;
|
|
1837
|
+
} else if (retMap.gradlePlugin) {
|
|
1838
|
+
gradlePluginBuilds.add(key);
|
|
1487
1839
|
}
|
|
1488
1840
|
gradleModules.set(key, rootComponent);
|
|
1489
|
-
if (
|
|
1841
|
+
if (
|
|
1842
|
+
!allProjectsAddedRefs.has(rootComponent["bom-ref"] ?? rootComponent)
|
|
1843
|
+
) {
|
|
1490
1844
|
allProjects.push(rootComponent);
|
|
1491
1845
|
rootDependsOn.add(rootComponent["bom-ref"]);
|
|
1492
|
-
|
|
1846
|
+
allProjectsAddedRefs.set(
|
|
1847
|
+
rootComponent["bom-ref"] ?? rootComponent,
|
|
1848
|
+
rootComponent,
|
|
1849
|
+
);
|
|
1493
1850
|
}
|
|
1494
1851
|
allProjectsStr = allProjectsStr.concat(retMap.projects);
|
|
1495
1852
|
}
|
|
@@ -1522,14 +1879,60 @@ export async function createJavaBom(path, options) {
|
|
|
1522
1879
|
);
|
|
1523
1880
|
const rootSubProject = retMap.rootProject;
|
|
1524
1881
|
if (rootSubProject) {
|
|
1882
|
+
// A subproject whose properties task printed nothing is named as
|
|
1883
|
+
// Gradle publishes it by default: the last segment of its path,
|
|
1884
|
+
// with the root project's group and version.
|
|
1885
|
+
if (!splitPropTaskOut.has(subProject)) {
|
|
1886
|
+
retMap.metadata.group ||= parentComponent?.group || "";
|
|
1887
|
+
if (
|
|
1888
|
+
retMap.metadata.version === "latest" &&
|
|
1889
|
+
parentComponent?.version
|
|
1890
|
+
) {
|
|
1891
|
+
retMap.metadata.version = parentComponent.version;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1525
1894
|
const rootSubProjectObj = await buildObjectForGradleModule(
|
|
1526
|
-
rootSubProject === "root"
|
|
1895
|
+
rootSubProject === "root"
|
|
1896
|
+
? subProject.split(":").pop()
|
|
1897
|
+
: rootSubProject,
|
|
1527
1898
|
retMap.metadata,
|
|
1528
1899
|
);
|
|
1529
|
-
|
|
1900
|
+
// Two subprojects that Gradle would publish under the same
|
|
1901
|
+
// coordinates, such as `:a:util` and `:b:util` with a shared group
|
|
1902
|
+
// and version, stay apart: the later one gets its project path as
|
|
1903
|
+
// the purl subpath. A module that shares the root project's
|
|
1904
|
+
// coordinates is the root's own artifact and merges with it.
|
|
1905
|
+
const holder = allProjectsAddedRefs.get(
|
|
1906
|
+
rootSubProjectObj["bom-ref"],
|
|
1907
|
+
);
|
|
1908
|
+
if (
|
|
1909
|
+
holder &&
|
|
1910
|
+
holder !== parentComponent &&
|
|
1911
|
+
holder !== gradleModules.get(subProject)
|
|
1912
|
+
) {
|
|
1913
|
+
const subpath = subProject.split(":").filter(Boolean).join("/");
|
|
1914
|
+
const distinctPurl = rootSubProjectObj.purl
|
|
1915
|
+
? tryBuildPurl({
|
|
1916
|
+
type: "maven",
|
|
1917
|
+
namespace: rootSubProjectObj.group || null,
|
|
1918
|
+
name: rootSubProjectObj.name,
|
|
1919
|
+
version: rootSubProjectObj.version || null,
|
|
1920
|
+
qualifiers: { type: "jar" },
|
|
1921
|
+
subpath,
|
|
1922
|
+
})
|
|
1923
|
+
: null;
|
|
1924
|
+
if (distinctPurl) {
|
|
1925
|
+
applyPurl(rootSubProjectObj, distinctPurl);
|
|
1926
|
+
} else {
|
|
1927
|
+
rootSubProjectObj["bom-ref"] =
|
|
1928
|
+
`${rootSubProjectObj["bom-ref"]}#${subpath}`;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
const moduleKey = rootSubProjectObj["bom-ref"] ?? rootSubProjectObj;
|
|
1932
|
+
if (!allProjectsAddedRefs.has(moduleKey)) {
|
|
1530
1933
|
allProjects.push(rootSubProjectObj);
|
|
1531
1934
|
rootDependsOn.add(rootSubProjectObj["bom-ref"]);
|
|
1532
|
-
|
|
1935
|
+
allProjectsAddedRefs.set(moduleKey, rootSubProjectObj);
|
|
1533
1936
|
}
|
|
1534
1937
|
gradleModules.set(subProject, rootSubProjectObj);
|
|
1535
1938
|
}
|
|
@@ -1546,14 +1949,39 @@ export async function createJavaBom(path, options) {
|
|
|
1546
1949
|
});
|
|
1547
1950
|
}
|
|
1548
1951
|
}
|
|
1952
|
+
if (gradleUseLockfiles) {
|
|
1953
|
+
const lockfileCount = addGradleLockfileComponents();
|
|
1954
|
+
if (lockfileCount) {
|
|
1955
|
+
console.log(
|
|
1956
|
+
`Using the dependencies locked by ${gradleLockFiles.length} Gradle lockfile(s) instead of executing 'gradle dependencies'.`,
|
|
1957
|
+
);
|
|
1958
|
+
thoughtLog(
|
|
1959
|
+
`Obtained ${lockfileCount} components from ${gradleLockFiles.length} Gradle lockfile(s). A lockfile is flat, so it says nothing about which module depends on which.`,
|
|
1960
|
+
);
|
|
1961
|
+
// --deep reads the jar namespaces of the versions the local Gradle
|
|
1962
|
+
// cache holds, as it does after a Gradle run; a cold cache yields
|
|
1963
|
+
// nothing.
|
|
1964
|
+
if (options.resolveClass || options.deep) {
|
|
1965
|
+
const tmpjarNSMapping = await collectJarNS(GRADLE_CACHE_DIR);
|
|
1966
|
+
if (tmpjarNSMapping && Object.keys(tmpjarNSMapping).length) {
|
|
1967
|
+
jarNSMapping = { ...jarNSMapping, ...tmpjarNSMapping };
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
} else {
|
|
1971
|
+
thoughtLog(
|
|
1972
|
+
"The Gradle lockfiles yielded no components, so the remaining static sources are tried.",
|
|
1973
|
+
);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
// Components that came from somewhere other than this Gradle run, such
|
|
1977
|
+
// as a Maven build in the same root, so the decisions below look only at
|
|
1978
|
+
// what Gradle itself produced.
|
|
1979
|
+
const pkgCountBeforeGradleRun = pkgList.length;
|
|
1549
1980
|
if (
|
|
1550
1981
|
gradleFiles?.length &&
|
|
1551
1982
|
options.installDeps &&
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
["maven", "bazel", "sbt", "mill"],
|
|
1555
|
-
options,
|
|
1556
|
-
)
|
|
1983
|
+
gradleManagerAllowed &&
|
|
1984
|
+
!gradleUseLockfiles
|
|
1557
1985
|
) {
|
|
1558
1986
|
allProjects.push(parentComponent);
|
|
1559
1987
|
const gradleCmd = getGradleCommand(gradleRootPath, null, options);
|
|
@@ -1561,7 +1989,6 @@ export async function createJavaBom(path, options) {
|
|
|
1561
1989
|
? readEnvironmentVariable("GRADLE_DEPENDENCY_TASK")
|
|
1562
1990
|
: "dependencies";
|
|
1563
1991
|
|
|
1564
|
-
const gradleSubCommands = [];
|
|
1565
1992
|
let modulesToSkip = readEnvironmentVariable("GRADLE_SKIP_MODULES")
|
|
1566
1993
|
? readEnvironmentVariable("GRADLE_SKIP_MODULES").split(",")
|
|
1567
1994
|
: [];
|
|
@@ -1570,23 +1997,16 @@ export async function createJavaBom(path, options) {
|
|
|
1570
1997
|
readEnvironmentVariable("GRADLE_SKIP_MODULE_DEPENDENCIES").split(","),
|
|
1571
1998
|
);
|
|
1572
1999
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
gradleSubCommands.push(`${key}:${gradleDepTask}`);
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
2000
|
+
const gradleSubCommands = gradleDependencyTasks(
|
|
2001
|
+
gradleModules,
|
|
2002
|
+
parentComponent,
|
|
2003
|
+
gradleDepTask,
|
|
2004
|
+
modulesToSkip,
|
|
2005
|
+
);
|
|
1582
2006
|
const gradleArguments = buildGradleCommandArguments(
|
|
1583
|
-
|
|
1584
|
-
? readEnvironmentVariable("GRADLE_ARGS").split(" ")
|
|
1585
|
-
: [],
|
|
2007
|
+
gradleArgsFromEnv("GRADLE_ARGS"),
|
|
1586
2008
|
gradleSubCommands,
|
|
1587
|
-
|
|
1588
|
-
? readEnvironmentVariable("GRADLE_ARGS_DEPENDENCIES").split(" ")
|
|
1589
|
-
: [],
|
|
2009
|
+
gradleArgsFromEnv("GRADLE_ARGS_DEPENDENCIES"),
|
|
1590
2010
|
gradleCmd.length,
|
|
1591
2011
|
);
|
|
1592
2012
|
const allOutputs = [];
|
|
@@ -1647,14 +2067,30 @@ export async function createJavaBom(path, options) {
|
|
|
1647
2067
|
const perProjectOutput = splitOutputByGradleProjects(cmdOutput, [
|
|
1648
2068
|
gradleDepTask,
|
|
1649
2069
|
]);
|
|
2070
|
+
await loadGradleModulesForReports(
|
|
2071
|
+
perProjectOutput.values(),
|
|
2072
|
+
gradleModules,
|
|
2073
|
+
gradleRootPath,
|
|
2074
|
+
options,
|
|
2075
|
+
);
|
|
2076
|
+
const reportedProjects = new Set(perProjectOutput.keys());
|
|
1650
2077
|
for (const key of gradleModules.keys()) {
|
|
1651
2078
|
const parsedList = await parseGradleDep(
|
|
1652
2079
|
perProjectOutput.has(key) ? perProjectOutput.get(key) : "",
|
|
1653
2080
|
key,
|
|
1654
2081
|
gradleModules,
|
|
1655
2082
|
gradleRootPath,
|
|
2083
|
+
reportedProjects,
|
|
1656
2084
|
);
|
|
1657
2085
|
const dlist = parsedList.pkgList;
|
|
2086
|
+
if (
|
|
2087
|
+
dlist?.length &&
|
|
2088
|
+
[...gradlePluginBuilds].some(
|
|
2089
|
+
(build) => key === build || key.startsWith(`${build}:`),
|
|
2090
|
+
)
|
|
2091
|
+
) {
|
|
2092
|
+
excludeGradleBuildTooling(dlist, gradleModules);
|
|
2093
|
+
}
|
|
1658
2094
|
if (parsedList?.dependenciesList?.length) {
|
|
1659
2095
|
dependencies = mergeDependencies(
|
|
1660
2096
|
dependencies,
|
|
@@ -1672,7 +2108,25 @@ export async function createJavaBom(path, options) {
|
|
|
1672
2108
|
pkgList = pkgList.concat(dlist);
|
|
1673
2109
|
}
|
|
1674
2110
|
}
|
|
2111
|
+
reconcileGradleComponents(pkgList);
|
|
1675
2112
|
}
|
|
2113
|
+
const gradleRunPkgCount = pkgList.length - pkgCountBeforeGradleRun;
|
|
2114
|
+
if (!gradleRunPkgCount && gradleLockFiles.length) {
|
|
2115
|
+
// Gradle produced no components of its own. The lockfiles are the
|
|
2116
|
+
// next source before the failure paths below: Gradle may have run
|
|
2117
|
+
// fine over configurations the project never locked, or failed
|
|
2118
|
+
// outright while the committed lockfiles still describe the build.
|
|
2119
|
+
const lockfileCount = addGradleLockfileComponents();
|
|
2120
|
+
if (lockfileCount) {
|
|
2121
|
+
thoughtLog(
|
|
2122
|
+
`Gradle produced no components, so the ${lockfileCount} components of ${gradleLockFiles.length} Gradle lockfile(s) were used instead.`,
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
// A catalog or verification fallback can supply these components when
|
|
2127
|
+
// Gradle produced none, so they pass through the same distribution and
|
|
2128
|
+
// subproject handling below.
|
|
2129
|
+
addGradleStaticFallbackComponents();
|
|
1676
2130
|
if (pkgList.length) {
|
|
1677
2131
|
const fileToUrlMap = parseGradleInfoLogsForUrls(sstdout);
|
|
1678
2132
|
// When the `resolve-gradle-distribution` feature flag is enabled, the init script
|
|
@@ -1685,9 +2139,15 @@ export async function createJavaBom(path, options) {
|
|
|
1685
2139
|
if (!p.externalReferences) {
|
|
1686
2140
|
p.externalReferences = [];
|
|
1687
2141
|
}
|
|
1688
|
-
|
|
2142
|
+
// The repository URLs name jar files, which a platform does not
|
|
2143
|
+
// have. The leading slash keeps group `foo` from matching a URL
|
|
2144
|
+
// under `org/foo/`.
|
|
2145
|
+
if (
|
|
2146
|
+
p.qualifiers?.type !== "pom" &&
|
|
2147
|
+
!p.externalReferences.find((r) => r.type === "distribution")
|
|
2148
|
+
) {
|
|
1689
2149
|
const groupPath = p.group.replace(/\./g, "/");
|
|
1690
|
-
const matchPath =
|
|
2150
|
+
const matchPath = `/${groupPath}/${p.name}/${p.version}/`;
|
|
1691
2151
|
let matchedUrl = Object.values(fileToUrlMap).find((url) =>
|
|
1692
2152
|
url.includes(matchPath),
|
|
1693
2153
|
);
|
|
@@ -1713,11 +2173,21 @@ export async function createJavaBom(path, options) {
|
|
|
1713
2173
|
}
|
|
1714
2174
|
}
|
|
1715
2175
|
thoughtLog(
|
|
1716
|
-
|
|
2176
|
+
gradleRunPkgCount
|
|
2177
|
+
? `Obtained ${pkgList.length} components by executing the '${basename(gradleCmd)}' command.`
|
|
2178
|
+
: `Obtained ${pkgList.length} components from the static Gradle sources after '${basename(gradleCmd)}' produced none.`,
|
|
1717
2179
|
);
|
|
1718
2180
|
if (DEBUG_MODE) {
|
|
1719
2181
|
console.log("Obtained", pkgList.length, "from this gradle project.");
|
|
1720
2182
|
}
|
|
2183
|
+
if (gradleRunPkgCount && gradleLockFiles.length) {
|
|
2184
|
+
// Gradle resolved against the lockfiles itself, so the versions it
|
|
2185
|
+
// reports already are the locked ones and parsing the files again
|
|
2186
|
+
// would add nothing.
|
|
2187
|
+
thoughtLog(
|
|
2188
|
+
`Gradle enforced the ${gradleLockFiles.length} Gradle lockfile(s) of this build, so they are not parsed separately.`,
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
1721
2191
|
} else if (hasGradleInvocationFailure()) {
|
|
1722
2192
|
// The invocation failure is already ranked, and an empty
|
|
1723
2193
|
// configuration is what that failure looks like from here: reporting
|
|
@@ -1783,37 +2253,25 @@ export async function createJavaBom(path, options) {
|
|
|
1783
2253
|
jarNSMapping = { ...jarNSMapping, ...tmpjarNSMapping };
|
|
1784
2254
|
}
|
|
1785
2255
|
}
|
|
1786
|
-
|
|
1787
|
-
// A version catalog declares coordinates without resolving them, so it
|
|
1788
|
-
// is used only when Gradle produced no dependency information at all.
|
|
1789
|
-
// The emitted components carry cdx:gradle:catalog=true to mark them as
|
|
1790
|
-
// declared rather than resolved.
|
|
1791
|
-
if (!pkgList.length) {
|
|
1792
|
-
const catalogFiles = getAllFiles(
|
|
1793
|
-
path,
|
|
1794
|
-
`${options.multiProject ? "**/" : ""}gradle/libs.versions.toml`,
|
|
1795
|
-
options,
|
|
1796
|
-
);
|
|
1797
|
-
for (const catalogFile of catalogFiles) {
|
|
1798
|
-
if (DEBUG_MODE) {
|
|
1799
|
-
console.log(`Parsing ${catalogFile}`);
|
|
1800
|
-
}
|
|
1801
|
-
const dlist = parseGradleVersionCatalog(catalogFile);
|
|
1802
|
-
if (dlist?.length) {
|
|
1803
|
-
pkgList = pkgList.concat(dlist);
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
2256
|
}
|
|
1808
2257
|
|
|
2258
|
+
// Outside the installDeps block on purpose: a scan with dependency
|
|
2259
|
+
// installation disabled reaches the static sources through the lockfile
|
|
2260
|
+
// path instead of the Gradle run, and a scan whose Gradle run was
|
|
2261
|
+
// skipped entirely needs them here.
|
|
2262
|
+
addGradleStaticFallbackComponents();
|
|
2263
|
+
|
|
1809
2264
|
// Bazel
|
|
1810
2265
|
// Look for the BUILD file only in the root directory
|
|
1811
2266
|
// NOTE: This can match BUILD files used by perl, so could lead to errors in some projects
|
|
2267
|
+
// A workspace under third_party/ or vendor/ is a copied project's: its
|
|
2268
|
+
// bazel_dep entries are that project's build tooling, and building it
|
|
2269
|
+
// would run its build.
|
|
1812
2270
|
const bazelFiles = getAllFiles(
|
|
1813
2271
|
path,
|
|
1814
2272
|
`${options.multiProject ? "**/" : ""}{WORKSPACE{,.bazel},MODULE.bazel}`,
|
|
1815
2273
|
options,
|
|
1816
|
-
);
|
|
2274
|
+
).filter((f) => !isInVendoredDir(path, f));
|
|
1817
2275
|
if (
|
|
1818
2276
|
bazelFiles?.length &&
|
|
1819
2277
|
!hasAnyProjectType(
|
|
@@ -1886,6 +2344,9 @@ export async function createJavaBom(path, options) {
|
|
|
1886
2344
|
) {
|
|
1887
2345
|
bArgs = ["--bazelrc=.bazelrc", "build", bazelTarget];
|
|
1888
2346
|
}
|
|
2347
|
+
// Repository rules see the mirror through their own environment,
|
|
2348
|
+
// which only a --repo_env flag reaches.
|
|
2349
|
+
bArgs = bArgs.concat(bazelMirrorArgs());
|
|
1889
2350
|
console.log("Executing", BAZEL_CMD, "in", basePath);
|
|
1890
2351
|
let result = safeSpawnSync(BAZEL_CMD, bArgs, {
|
|
1891
2352
|
cwd: basePath,
|
|
@@ -2099,7 +2560,7 @@ export async function createJavaBom(path, options) {
|
|
|
2099
2560
|
// sbt resolves into the user's own caches, so a project that has been
|
|
2100
2561
|
// built resolves without the network. The dependency trees download
|
|
2101
2562
|
// the jar of every dependency they list, which is all --deep reads.
|
|
2102
|
-
const env = { ...process.env };
|
|
2563
|
+
const env = { ...process.env, ...sbtMirrorEnv() };
|
|
2103
2564
|
for (const i in sbtProjects) {
|
|
2104
2565
|
if (isBuildToolRateLimited("sbt")) {
|
|
2105
2566
|
// Every remaining sbt build in this scan resolves from the same
|
|
@@ -2450,19 +2911,13 @@ export async function createJavaBom(path, options) {
|
|
|
2450
2911
|
const jarNSData = await createJarBom(path, options);
|
|
2451
2912
|
if (jarNSData?.bomJson?.components) {
|
|
2452
2913
|
pkgList = pkgList.concat(jarNSData?.bomJson?.components);
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
);
|
|
2461
|
-
if (nsProp.length) {
|
|
2462
|
-
targetJarNSMapping[p.purl] = nsProp[0].value;
|
|
2463
|
-
}
|
|
2464
|
-
}
|
|
2465
|
-
jarNSMapping = { ...jarNSMapping, ...targetJarNSMapping };
|
|
2914
|
+
jarNSMapping = {
|
|
2915
|
+
...jarNSMapping,
|
|
2916
|
+
...namespaceMappingOfComponents(
|
|
2917
|
+
jarNSData.bomJson.components,
|
|
2918
|
+
jarNSMapping,
|
|
2919
|
+
),
|
|
2920
|
+
};
|
|
2466
2921
|
}
|
|
2467
2922
|
}
|
|
2468
2923
|
}
|
|
@@ -2504,10 +2959,12 @@ export async function createJavaBom(path, options) {
|
|
|
2504
2959
|
if (DEBUG_MODE) {
|
|
2505
2960
|
console.log("Executing", millCmd, "in", millRootPath);
|
|
2506
2961
|
}
|
|
2962
|
+
const millSpawnEnv = { ...process.env, ...coursierMirrorEnv() };
|
|
2507
2963
|
let sresult = safeSpawnSync(millCmd, millArgs, {
|
|
2508
2964
|
cwd: millRootPath,
|
|
2509
2965
|
shell: isWin,
|
|
2510
2966
|
maxBuffer: MAX_BUFFER * 10,
|
|
2967
|
+
env: millSpawnEnv,
|
|
2511
2968
|
});
|
|
2512
2969
|
noteBuildToolRateLimit("mill", commandOutputText(sresult), {
|
|
2513
2970
|
command: `${basename(millCmd)} ${millArgs.join(" ")}`,
|
|
@@ -2546,6 +3003,7 @@ export async function createJavaBom(path, options) {
|
|
|
2546
3003
|
sresult = safeSpawnSync(millCmd, millResolveArgs, {
|
|
2547
3004
|
cwd: millRootPath,
|
|
2548
3005
|
shell: isWin,
|
|
3006
|
+
env: millSpawnEnv,
|
|
2549
3007
|
});
|
|
2550
3008
|
if (sresult.status !== 0 || sresult.error) {
|
|
2551
3009
|
if (options.failOnError || DEBUG_MODE) {
|
|
@@ -2710,12 +3168,70 @@ export async function createJavaBom(path, options) {
|
|
|
2710
3168
|
// Deduplication and metadata belong to whatever was collected, so they run
|
|
2711
3169
|
// on the deferred path too.
|
|
2712
3170
|
pkgList = trimComponents(pkgList);
|
|
3171
|
+
// A library the build tool reported and a jar on disk named again is one
|
|
3172
|
+
// component, wherever the jar scan spelled it differently. The jar
|
|
3173
|
+
// namespace map follows the purls the merge settled on.
|
|
3174
|
+
const scalaMerge = mergeScalaDuplicateComponents(pkgList, dependencies);
|
|
3175
|
+
pkgList = scalaMerge.components;
|
|
3176
|
+
dependencies = scalaMerge.dependencies;
|
|
3177
|
+
jarNSMapping = rekeyNamespaceMapping(jarNSMapping, scalaMerge.purlMap);
|
|
2713
3178
|
// --deep collects namespaces; it does not opt in to remote licence lookups,
|
|
2714
3179
|
// which FETCH_LICENSE controls. The project's own modules are never looked
|
|
2715
3180
|
// up remotely: they are not published.
|
|
2716
3181
|
pkgList = await getMvnMetadata(pkgList, jarNSMapping, false, {
|
|
2717
3182
|
skipPurls: ownComponentRefs(parentComponent),
|
|
2718
3183
|
});
|
|
3184
|
+
// The verification file is the last enrichment, after getMvnMetadata has
|
|
3185
|
+
// hashed the jars of the local cache: a digest of the artifact itself is
|
|
3186
|
+
// the stronger claim, so the recorded digests only fill the algorithms a
|
|
3187
|
+
// component still lacks, and a differing digest of the same algorithm is
|
|
3188
|
+
// flagged, never applied. Whatever source found the component keeps the
|
|
3189
|
+
// identity evidence of that source.
|
|
3190
|
+
if (gradleVerificationFile) {
|
|
3191
|
+
const verificationMetadata = gradleVerification();
|
|
3192
|
+
if (verificationMetadata) {
|
|
3193
|
+
const enrichedCount = applyGradleVerificationMetadata(
|
|
3194
|
+
pkgList,
|
|
3195
|
+
verificationMetadata,
|
|
3196
|
+
gradleVerificationFile,
|
|
3197
|
+
);
|
|
3198
|
+
if (enrichedCount) {
|
|
3199
|
+
thoughtLog(
|
|
3200
|
+
`Enriched ${enrichedCount} component(s) with the checksums that ${gradleVerificationFile} records.`,
|
|
3201
|
+
);
|
|
3202
|
+
}
|
|
3203
|
+
// Whether Gradle verified metadata and signatures is a fact about the
|
|
3204
|
+
// whole build, so it lands on the primary component. Only the flags
|
|
3205
|
+
// the file actually writes are emitted.
|
|
3206
|
+
const { configuration } = verificationMetadata;
|
|
3207
|
+
if (parentComponent && Object.keys(parentComponent).length) {
|
|
3208
|
+
const parentProperties = parentComponent.properties || [];
|
|
3209
|
+
if (
|
|
3210
|
+
configuration.verifyMetadata !== undefined &&
|
|
3211
|
+
!parentProperties.some((p) => p.name === "cdx:gradle:verifyMetadata")
|
|
3212
|
+
) {
|
|
3213
|
+
parentProperties.push({
|
|
3214
|
+
name: "cdx:gradle:verifyMetadata",
|
|
3215
|
+
value: String(configuration.verifyMetadata),
|
|
3216
|
+
});
|
|
3217
|
+
}
|
|
3218
|
+
if (
|
|
3219
|
+
configuration.verifySignatures !== undefined &&
|
|
3220
|
+
!parentProperties.some(
|
|
3221
|
+
(p) => p.name === "cdx:gradle:verifySignatures",
|
|
3222
|
+
)
|
|
3223
|
+
) {
|
|
3224
|
+
parentProperties.push({
|
|
3225
|
+
name: "cdx:gradle:verifySignatures",
|
|
3226
|
+
value: String(configuration.verifySignatures),
|
|
3227
|
+
});
|
|
3228
|
+
}
|
|
3229
|
+
if (parentProperties.length) {
|
|
3230
|
+
parentComponent.properties = parentProperties;
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
2719
3235
|
return buildBomNSData(options, pkgList, "maven", {
|
|
2720
3236
|
src: path,
|
|
2721
3237
|
nsMapping: jarNSMapping,
|