@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
|
@@ -16,6 +16,7 @@ import { build, Purl } from "@cdxgen/cdx-purl";
|
|
|
16
16
|
// utils.js does not import rubyutils.js, so importing from it here is safe and
|
|
17
17
|
// does not introduce a cyclic dependency.
|
|
18
18
|
import { DEBUG_MODE, readEnvironmentVariable } from "../core/activity.js";
|
|
19
|
+
import { readRegularTextFile } from "../core/boundedFile.js";
|
|
19
20
|
import { shouldFetchLicense } from "../core/env.js";
|
|
20
21
|
import { getAllFiles, safeExistsSync, safeSpawnSync } from "../core/fs.js";
|
|
21
22
|
import { thoughtLog } from "../core/logger.js";
|
|
@@ -29,6 +30,11 @@ import {
|
|
|
29
30
|
recordPolicyDegradationFromError,
|
|
30
31
|
} from "../inventory/fetchBatch.js";
|
|
31
32
|
import { genericPurl } from "../inventory/purl.js";
|
|
33
|
+
import {
|
|
34
|
+
createRubyRuntimeComponent,
|
|
35
|
+
defaultGemInstall,
|
|
36
|
+
parseRubyVersion,
|
|
37
|
+
} from "../inventory/rubyBuildInfo.js";
|
|
32
38
|
import { isValidIdnEmail } from "../parsers/email.js";
|
|
33
39
|
|
|
34
40
|
// FIXME. This has to get removed, once we improve the module detection one-liner.
|
|
@@ -1563,6 +1569,40 @@ function listGemBindirFiles(gemspecFile, bindir = "bin") {
|
|
|
1563
1569
|
}
|
|
1564
1570
|
}
|
|
1565
1571
|
|
|
1572
|
+
/**
|
|
1573
|
+
* Whether gemspec text is really a Marshal dump. RubyGems' spec cache stores
|
|
1574
|
+
* Marshal-dumped specifications in files named `<gem>-<version>.gemspec`; they
|
|
1575
|
+
* start with the Marshal 4.8 header bytes 0x04 0x08 and hold no Ruby source to
|
|
1576
|
+
* parse, so reading one would leave only the file name to guess from.
|
|
1577
|
+
*
|
|
1578
|
+
* @param {string} gemspecData file contents
|
|
1579
|
+
* @returns {boolean} true for a Marshal dump
|
|
1580
|
+
*/
|
|
1581
|
+
function isMarshalData(gemspecData) {
|
|
1582
|
+
return (
|
|
1583
|
+
typeof gemspecData === "string" &&
|
|
1584
|
+
gemspecData.charCodeAt(0) === 4 &&
|
|
1585
|
+
gemspecData.charCodeAt(1) === 8
|
|
1586
|
+
);
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
/**
|
|
1590
|
+
* Whether a gemspec is a default gem, one that ships with Ruby: RubyGems
|
|
1591
|
+
* keeps them under `specifications/default/`.
|
|
1592
|
+
*
|
|
1593
|
+
* @param {string} gemspecFile path of the gemspec, either separator
|
|
1594
|
+
* @returns {boolean}
|
|
1595
|
+
*/
|
|
1596
|
+
export function isDefaultGemspecPath(gemspecFile) {
|
|
1597
|
+
if (typeof gemspecFile !== "string") {
|
|
1598
|
+
return false;
|
|
1599
|
+
}
|
|
1600
|
+
return (
|
|
1601
|
+
defaultGemInstall(gemspecFile) !== undefined ||
|
|
1602
|
+
gemspecFile.replaceAll("\\", "/").includes("/specifications/default/")
|
|
1603
|
+
);
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1566
1606
|
/**
|
|
1567
1607
|
* Method to parse Gemspec file contents.
|
|
1568
1608
|
*
|
|
@@ -1594,7 +1634,7 @@ export async function parseGemspecData(gemspecData, gemspecFile, options = {}) {
|
|
|
1594
1634
|
if (gemspecFile) {
|
|
1595
1635
|
pkg.name = basename(gemspecFile).replace(".gemspec", "");
|
|
1596
1636
|
}
|
|
1597
|
-
if (!gemspecData) {
|
|
1637
|
+
if (!gemspecData || isMarshalData(gemspecData)) {
|
|
1598
1638
|
return pkgList;
|
|
1599
1639
|
}
|
|
1600
1640
|
let versionHackMatch = false;
|
|
@@ -1949,6 +1989,12 @@ export async function parseGemspecData(gemspecData, gemspecFile, options = {}) {
|
|
|
1949
1989
|
}
|
|
1950
1990
|
if (gemspecFile) {
|
|
1951
1991
|
pkg.properties.push({ name: "internal:SrcFile", value: gemspecFile });
|
|
1992
|
+
// RubyGems keeps the gems that ship with Ruby itself, such as resolv and
|
|
1993
|
+
// net-http, under specifications/default. They are updated with Ruby, so
|
|
1994
|
+
// their advisories are often fixed by a Ruby release.
|
|
1995
|
+
if (isDefaultGemspecPath(gemspecFile)) {
|
|
1996
|
+
pkg.properties.push({ name: "cdx:gem:defaultGem", value: "true" });
|
|
1997
|
+
}
|
|
1952
1998
|
// Did we find the version number from the directory name? Let's reduce the confidence and set the correct technique
|
|
1953
1999
|
pkg.evidence = {
|
|
1954
2000
|
identity: {
|
|
@@ -2861,30 +2907,434 @@ export function rubyRequirementToVers(requirements) {
|
|
|
2861
2907
|
return `vers:gem/${constraints.map((c) => c.text).join("|")}`;
|
|
2862
2908
|
}
|
|
2863
2909
|
|
|
2910
|
+
// Ruby engines a version manager or Bundler can name. MRI is `ruby`.
|
|
2911
|
+
const RUBY_ENGINES = new Set(["ruby", "jruby", "truffleruby"]);
|
|
2912
|
+
const MAX_PIN_FILE_BYTES = 64 * 1024;
|
|
2913
|
+
const MAX_GEMFILE_BYTES = 1024 * 1024;
|
|
2914
|
+
const MAX_LOCKFILE_BYTES = 16 * 1024 * 1024;
|
|
2915
|
+
|
|
2916
|
+
// An exact version, or a partial one such as `3.3` that pins a series and is
|
|
2917
|
+
// read as the requirement `~> 3.3.0`.
|
|
2918
|
+
function rubyPin(engine, text, source) {
|
|
2919
|
+
const value = `${text || ""}`.trim();
|
|
2920
|
+
if (!value || value.length > 64) {
|
|
2921
|
+
return undefined;
|
|
2922
|
+
}
|
|
2923
|
+
if (engine === "ruby") {
|
|
2924
|
+
const version = parseRubyVersion(value);
|
|
2925
|
+
if (version) {
|
|
2926
|
+
return { engine, version, source };
|
|
2927
|
+
}
|
|
2928
|
+
if (/^\d+\.\d+$/.test(value)) {
|
|
2929
|
+
return { engine, requirement: `~> ${value}.0`, source };
|
|
2930
|
+
}
|
|
2931
|
+
if (/^\d+$/.test(value)) {
|
|
2932
|
+
return { engine, requirement: `~> ${value}.0`, source };
|
|
2933
|
+
}
|
|
2934
|
+
return undefined;
|
|
2935
|
+
}
|
|
2936
|
+
return /^\d+(\.\d+){1,3}$/.test(value)
|
|
2937
|
+
? { engine, version: value, source }
|
|
2938
|
+
: undefined;
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2864
2941
|
/**
|
|
2865
|
-
*
|
|
2942
|
+
* Read the Ruby a `.ruby-version` file selects, as rbenv, chruby, rvm, asdf
|
|
2943
|
+
* and mise read it: `3.3.6`, `ruby-3.3.6`, `3.3`, `jruby-9.4.8.0`,
|
|
2944
|
+
* `truffleruby-24.1.0`, `truffleruby+graalvm-24.1.0`. Only the first word
|
|
2945
|
+
* counts; comments and blank lines are skipped.
|
|
2946
|
+
*
|
|
2947
|
+
* @param {string} text file contents
|
|
2948
|
+
* @returns {{engine: string, version?: string, requirement?: string, source: string}|undefined}
|
|
2949
|
+
*/
|
|
2950
|
+
export function parseRubyVersionFile(text) {
|
|
2951
|
+
if (typeof text !== "string") {
|
|
2952
|
+
return undefined;
|
|
2953
|
+
}
|
|
2954
|
+
for (const rawLine of text.slice(0, MAX_PIN_FILE_BYTES).split(/\r?\n/)) {
|
|
2955
|
+
const line = rawLine.split("#")[0].trim().split(/\s+/)[0];
|
|
2956
|
+
if (!line) {
|
|
2957
|
+
continue;
|
|
2958
|
+
}
|
|
2959
|
+
const dash = line.indexOf("-");
|
|
2960
|
+
if (dash > 0 && !/^\d/.test(line)) {
|
|
2961
|
+
const engine = line.slice(0, dash).split("+")[0];
|
|
2962
|
+
if (!RUBY_ENGINES.has(engine)) {
|
|
2963
|
+
return undefined;
|
|
2964
|
+
}
|
|
2965
|
+
return rubyPin(engine, line.slice(dash + 1), ".ruby-version");
|
|
2966
|
+
}
|
|
2967
|
+
return rubyPin("ruby", line, ".ruby-version");
|
|
2968
|
+
}
|
|
2969
|
+
return undefined;
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
/**
|
|
2973
|
+
* Read the Ruby an asdf `.tool-versions` file selects: the first version on
|
|
2974
|
+
* the `ruby` line, e.g. `ruby 3.3.6 3.2.2`.
|
|
2975
|
+
*
|
|
2976
|
+
* @param {string} text file contents
|
|
2977
|
+
* @returns {{engine: string, version?: string, requirement?: string, source: string}|undefined}
|
|
2978
|
+
*/
|
|
2979
|
+
export function parseToolVersionsRuby(text) {
|
|
2980
|
+
if (typeof text !== "string") {
|
|
2981
|
+
return undefined;
|
|
2982
|
+
}
|
|
2983
|
+
for (const rawLine of text.slice(0, MAX_PIN_FILE_BYTES).split(/\r?\n/)) {
|
|
2984
|
+
const words = rawLine.split("#")[0].trim().split(/\s+/);
|
|
2985
|
+
if (words[0] !== "ruby" || !words[1]) {
|
|
2986
|
+
continue;
|
|
2987
|
+
}
|
|
2988
|
+
const value = words[1];
|
|
2989
|
+
const dash = value.indexOf("-");
|
|
2990
|
+
if (dash > 0 && !/^\d/.test(value)) {
|
|
2991
|
+
const engine = value.slice(0, dash).split("+")[0];
|
|
2992
|
+
return RUBY_ENGINES.has(engine)
|
|
2993
|
+
? rubyPin(engine, value.slice(dash + 1), ".tool-versions")
|
|
2994
|
+
: undefined;
|
|
2995
|
+
}
|
|
2996
|
+
return rubyPin("ruby", value, ".tool-versions");
|
|
2997
|
+
}
|
|
2998
|
+
return undefined;
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
/**
|
|
3002
|
+
* Read the Ruby a mise configuration selects from its `[tools]` table:
|
|
3003
|
+
* `ruby = "3.3.6"`, `ruby = ["3.3.6", "3.2"]` or `ruby = { version = "3.3.6" }`.
|
|
3004
|
+
*
|
|
3005
|
+
* @param {string} text mise.toml contents
|
|
3006
|
+
* @param {string} [source="mise.toml"] the file name, for the result
|
|
3007
|
+
* @returns {{engine: string, version?: string, requirement?: string, source: string}|undefined}
|
|
3008
|
+
*/
|
|
3009
|
+
export function parseMiseRuby(text, source = "mise.toml") {
|
|
3010
|
+
if (typeof text !== "string") {
|
|
3011
|
+
return undefined;
|
|
3012
|
+
}
|
|
3013
|
+
let inTools = false;
|
|
3014
|
+
for (const rawLine of text.slice(0, MAX_PIN_FILE_BYTES).split(/\r?\n/)) {
|
|
3015
|
+
const line = rawLine.trim();
|
|
3016
|
+
if (line.startsWith("[")) {
|
|
3017
|
+
// `[tools]`, `[ tools ]` and `[tools] # pinned` open the same table
|
|
3018
|
+
inTools = line.split("#")[0].replace(/\s+/g, "") === "[tools]";
|
|
3019
|
+
continue;
|
|
3020
|
+
}
|
|
3021
|
+
if (!inTools || !/^["']?ruby["']?\s*=/.test(line)) {
|
|
3022
|
+
continue;
|
|
3023
|
+
}
|
|
3024
|
+
const value = line.slice(line.indexOf("=") + 1).trim();
|
|
3025
|
+
const quoted = /["']([^"']+)["']/.exec(
|
|
3026
|
+
value.startsWith("{") ? value.slice(value.indexOf("version")) : value,
|
|
3027
|
+
);
|
|
3028
|
+
return quoted ? rubyPin("ruby", quoted[1], source) : undefined;
|
|
3029
|
+
}
|
|
3030
|
+
return undefined;
|
|
3031
|
+
}
|
|
3032
|
+
|
|
3033
|
+
/**
|
|
3034
|
+
* Read the `ruby` directive of a Gemfile: `ruby "3.3.6"`, `ruby "~> 3.3"`,
|
|
3035
|
+
* `ruby "3.1.4", engine: "jruby", engine_version: "9.4.8.0"`, or
|
|
3036
|
+
* `ruby file: ".ruby-version"`. The Gemfile is never evaluated, so a
|
|
3037
|
+
* directive built from an expression, such as `ruby RUBY_VERSION`, says
|
|
3038
|
+
* nothing.
|
|
3039
|
+
*
|
|
3040
|
+
* @param {string} text Gemfile contents
|
|
3041
|
+
* @returns {{engine: string, version?: string, requirement?: string,
|
|
3042
|
+
* file?: string, source: string}|undefined}
|
|
3043
|
+
*/
|
|
3044
|
+
export function parseGemfileRubyDirective(text) {
|
|
3045
|
+
if (typeof text !== "string") {
|
|
3046
|
+
return undefined;
|
|
3047
|
+
}
|
|
3048
|
+
for (const rawLine of text.slice(0, 1024 * 1024).split(/\r?\n/)) {
|
|
3049
|
+
const line = rawLine.trim();
|
|
3050
|
+
if (!/^ruby[\s(]/.test(line)) {
|
|
3051
|
+
continue;
|
|
3052
|
+
}
|
|
3053
|
+
let rest = line.slice(4).trim();
|
|
3054
|
+
if (rest.startsWith("(")) {
|
|
3055
|
+
rest = rest.slice(1).trim();
|
|
3056
|
+
}
|
|
3057
|
+
const fileMatch = /^file:\s*/.exec(rest);
|
|
3058
|
+
if (fileMatch) {
|
|
3059
|
+
const literal = readRubyStringLiteral(rest.slice(fileMatch[0].length));
|
|
3060
|
+
return literal?.value && !literal.interpolated
|
|
3061
|
+
? { engine: "ruby", file: literal.value, source: "Gemfile" }
|
|
3062
|
+
: undefined;
|
|
3063
|
+
}
|
|
3064
|
+
const literal = readRubyStringLiteral(rest);
|
|
3065
|
+
if (!literal?.value || literal.interpolated) {
|
|
3066
|
+
return undefined;
|
|
3067
|
+
}
|
|
3068
|
+
// `ruby "3.2.2" if ENV["LEGACY"]` holds only on some machines; a later
|
|
3069
|
+
// unconditional directive, if any, is the project's.
|
|
3070
|
+
if (/(^|[\s,)])(if|unless)\s/.test(literal.rest)) {
|
|
3071
|
+
continue;
|
|
3072
|
+
}
|
|
3073
|
+
const keyword = (name) => {
|
|
3074
|
+
const index = rest.indexOf(`${name}:`);
|
|
3075
|
+
if (index === -1) {
|
|
3076
|
+
return undefined;
|
|
3077
|
+
}
|
|
3078
|
+
const value = readRubyStringLiteral(
|
|
3079
|
+
rest.slice(index + name.length + 1).trim(),
|
|
3080
|
+
);
|
|
3081
|
+
return value && !value.interpolated ? value.value : undefined;
|
|
3082
|
+
};
|
|
3083
|
+
const engine = keyword("engine");
|
|
3084
|
+
const engineVersion = keyword("engine_version");
|
|
3085
|
+
if (engine && engine !== "ruby") {
|
|
3086
|
+
if (!RUBY_ENGINES.has(engine) || !engineVersion) {
|
|
3087
|
+
return undefined;
|
|
3088
|
+
}
|
|
3089
|
+
const pin = rubyPin(engine, engineVersion, "Gemfile");
|
|
3090
|
+
return pin ? { ...pin, rubyVersion: literal.value } : undefined;
|
|
3091
|
+
}
|
|
3092
|
+
const value = literal.value.trim();
|
|
3093
|
+
const exact = parseRubyVersion(value);
|
|
3094
|
+
if (exact) {
|
|
3095
|
+
return { engine: "ruby", version: exact, source: "Gemfile" };
|
|
3096
|
+
}
|
|
3097
|
+
return rubyRequirementToVers([value]) !== undefined
|
|
3098
|
+
? { engine: "ruby", requirement: value, source: "Gemfile" }
|
|
3099
|
+
: undefined;
|
|
3100
|
+
}
|
|
3101
|
+
return undefined;
|
|
3102
|
+
}
|
|
3103
|
+
|
|
3104
|
+
/**
|
|
3105
|
+
* Read the `RUBY VERSION` section of a Gemfile.lock, which Bundler writes when
|
|
3106
|
+
* the Gemfile has a `ruby` directive: `ruby 3.3.6p108`, `ruby 3.4.0p-1` for a
|
|
3107
|
+
* pre-release, or `ruby 3.1.4p0 (jruby 9.4.8.0)` for another engine.
|
|
3108
|
+
*
|
|
3109
|
+
* @param {string} text Gemfile.lock contents
|
|
3110
|
+
* @returns {{engine: string, version: string, patchlevel?: string,
|
|
3111
|
+
* rubyVersion?: string, source: string}|undefined}
|
|
3112
|
+
*/
|
|
3113
|
+
export function parseGemfileLockRubyVersion(text) {
|
|
3114
|
+
if (typeof text !== "string") {
|
|
3115
|
+
return undefined;
|
|
3116
|
+
}
|
|
3117
|
+
const lines = text.split(/\r?\n/);
|
|
3118
|
+
for (let index = 0; index < lines.length; index++) {
|
|
3119
|
+
if (lines[index].trim() !== "RUBY VERSION") {
|
|
3120
|
+
continue;
|
|
3121
|
+
}
|
|
3122
|
+
const value = (lines[index + 1] || "").trim();
|
|
3123
|
+
const match =
|
|
3124
|
+
/^ruby (\d+\.\d+\.\d+)(?:p(-?\d+))?(?: \((jruby|truffleruby) (\d+(?:\.\d+){1,3})\))?$/.exec(
|
|
3125
|
+
value,
|
|
3126
|
+
);
|
|
3127
|
+
if (!match) {
|
|
3128
|
+
return undefined;
|
|
3129
|
+
}
|
|
3130
|
+
if (match[3]) {
|
|
3131
|
+
return {
|
|
3132
|
+
engine: match[3],
|
|
3133
|
+
version: match[4],
|
|
3134
|
+
rubyVersion: match[1],
|
|
3135
|
+
source: "Gemfile.lock",
|
|
3136
|
+
};
|
|
3137
|
+
}
|
|
3138
|
+
const result = {
|
|
3139
|
+
engine: "ruby",
|
|
3140
|
+
version: match[1],
|
|
3141
|
+
source: "Gemfile.lock",
|
|
3142
|
+
};
|
|
3143
|
+
if (match[2] !== undefined && match[2] !== "-1") {
|
|
3144
|
+
result.patchlevel = match[2];
|
|
3145
|
+
} else if (match[2] === "-1") {
|
|
3146
|
+
// A pre-release or development build, whose tag Bundler does not record
|
|
3147
|
+
result.prerelease = true;
|
|
3148
|
+
}
|
|
3149
|
+
return result;
|
|
3150
|
+
}
|
|
3151
|
+
return undefined;
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
// A pin file is read only when it is a regular file inside the project and
|
|
3155
|
+
// within a size cap: a repository can commit `.tool-versions -> /dev/zero` or
|
|
3156
|
+
// a FIFO, which an unbounded read would never finish.
|
|
3157
|
+
function readPinFile(file, projectRoot, maxBytes = MAX_PIN_FILE_BYTES) {
|
|
3158
|
+
return readRegularTextFile(file, maxBytes, projectRoot);
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
/**
|
|
3162
|
+
* Collect every Ruby a project directory declares, from the Gemfile.lock
|
|
3163
|
+
* `RUBY VERSION` section, `.ruby-version`, `.tool-versions`, mise.toml and the
|
|
3164
|
+
* Gemfile `ruby` directive. Each declaration names its source.
|
|
3165
|
+
*
|
|
3166
|
+
* @param {string} projectPath project directory
|
|
3167
|
+
* @param {string} [lockData] Gemfile.lock contents, when already read
|
|
3168
|
+
* @returns {Array<{engine: string, version?: string, requirement?: string,
|
|
3169
|
+
* patchlevel?: string, source: string, path: string}>}
|
|
3170
|
+
*/
|
|
3171
|
+
export function collectProjectRubyDeclarations(projectPath, lockData) {
|
|
3172
|
+
const declarations = [];
|
|
3173
|
+
const add = (declaration, path) => {
|
|
3174
|
+
if (declaration) {
|
|
3175
|
+
declarations.push({ ...declaration, path });
|
|
3176
|
+
}
|
|
3177
|
+
};
|
|
3178
|
+
const lockFile = join(projectPath, "Gemfile.lock");
|
|
3179
|
+
add(
|
|
3180
|
+
parseGemfileLockRubyVersion(
|
|
3181
|
+
lockData === undefined
|
|
3182
|
+
? readPinFile(lockFile, projectPath, MAX_LOCKFILE_BYTES)
|
|
3183
|
+
: lockData,
|
|
3184
|
+
),
|
|
3185
|
+
lockFile,
|
|
3186
|
+
);
|
|
3187
|
+
const versionFile = join(projectPath, ".ruby-version");
|
|
3188
|
+
add(parseRubyVersionFile(readPinFile(versionFile, projectPath)), versionFile);
|
|
3189
|
+
const toolVersions = join(projectPath, ".tool-versions");
|
|
3190
|
+
add(
|
|
3191
|
+
parseToolVersionsRuby(readPinFile(toolVersions, projectPath)),
|
|
3192
|
+
toolVersions,
|
|
3193
|
+
);
|
|
3194
|
+
for (const name of ["mise.toml", ".mise.toml", ".config/mise.toml"]) {
|
|
3195
|
+
const miseFile = join(projectPath, name);
|
|
3196
|
+
add(parseMiseRuby(readPinFile(miseFile, projectPath), name), miseFile);
|
|
3197
|
+
}
|
|
3198
|
+
const gemfile = join(projectPath, "Gemfile");
|
|
3199
|
+
const directive = parseGemfileRubyDirective(
|
|
3200
|
+
readPinFile(gemfile, projectPath, MAX_GEMFILE_BYTES),
|
|
3201
|
+
);
|
|
3202
|
+
if (directive?.file) {
|
|
3203
|
+
// `ruby file: ".ruby-version"` reads the version from that file, relative
|
|
3204
|
+
// to the Gemfile; a path out of the project is not followed.
|
|
3205
|
+
const target = resolve(projectPath, directive.file);
|
|
3206
|
+
const inside = relative(resolve(projectPath), target);
|
|
3207
|
+
if (inside && !inside.startsWith("..") && !isAbsolute(inside)) {
|
|
3208
|
+
// Bundler reads .tool-versions and mise.toml through `ruby file:` too
|
|
3209
|
+
const text = readPinFile(target, projectPath);
|
|
3210
|
+
const name = basename(target);
|
|
3211
|
+
const fromFile =
|
|
3212
|
+
name === ".tool-versions"
|
|
3213
|
+
? parseToolVersionsRuby(text)
|
|
3214
|
+
: name.endsWith(".toml")
|
|
3215
|
+
? parseMiseRuby(text)
|
|
3216
|
+
: parseRubyVersionFile(text);
|
|
3217
|
+
add(fromFile ? { ...fromFile, source: "Gemfile" } : undefined, gemfile);
|
|
3218
|
+
}
|
|
3219
|
+
} else {
|
|
3220
|
+
add(directive, gemfile);
|
|
3221
|
+
}
|
|
3222
|
+
return declarations;
|
|
3223
|
+
}
|
|
3224
|
+
|
|
3225
|
+
// The Ruby a lockfile was resolved with is what the project ran on; the pin
|
|
3226
|
+
// files say what developers select; the Gemfile says what Bundler accepts.
|
|
3227
|
+
const DECLARATION_PRECEDENCE = [
|
|
3228
|
+
"Gemfile.lock",
|
|
3229
|
+
".ruby-version",
|
|
3230
|
+
".tool-versions",
|
|
3231
|
+
"mise.toml",
|
|
3232
|
+
".mise.toml",
|
|
3233
|
+
".config/mise.toml",
|
|
3234
|
+
"Gemfile",
|
|
3235
|
+
];
|
|
3236
|
+
|
|
3237
|
+
/**
|
|
3238
|
+
* Settle the Ruby a project runs on from its declarations: the exact version
|
|
3239
|
+
* of the most authoritative source that has one, and the requirements of the
|
|
3240
|
+
* sources that only constrain it.
|
|
3241
|
+
*
|
|
3242
|
+
* @param {Array<Object>} declarations result of collectProjectRubyDeclarations
|
|
3243
|
+
* @returns {{engine: string, version?: string, patchlevel?: string,
|
|
3244
|
+
* prerelease?: boolean, rubyVersion?: string, source?: string,
|
|
3245
|
+
* requirements: string[], conflicts: string[]}|undefined}
|
|
3246
|
+
*/
|
|
3247
|
+
export function resolveProjectRuby(declarations) {
|
|
3248
|
+
if (!declarations?.length) {
|
|
3249
|
+
return undefined;
|
|
3250
|
+
}
|
|
3251
|
+
const ordered = [...declarations].sort(
|
|
3252
|
+
(a, b) =>
|
|
3253
|
+
DECLARATION_PRECEDENCE.indexOf(a.source) -
|
|
3254
|
+
DECLARATION_PRECEDENCE.indexOf(b.source),
|
|
3255
|
+
);
|
|
3256
|
+
let exact = ordered.find((declaration) => declaration.version);
|
|
3257
|
+
// Bundler records a pre-release as `ruby 3.4.0p-1`, without its tag. A pin
|
|
3258
|
+
// that names the tag of that same version says which pre-release it is.
|
|
3259
|
+
const lockedPrerelease = exact?.prerelease ? exact : undefined;
|
|
3260
|
+
if (lockedPrerelease) {
|
|
3261
|
+
exact =
|
|
3262
|
+
ordered.find(
|
|
3263
|
+
(declaration) =>
|
|
3264
|
+
declaration.engine === lockedPrerelease.engine &&
|
|
3265
|
+
declaration.version?.startsWith(`${lockedPrerelease.version}-`),
|
|
3266
|
+
) || lockedPrerelease;
|
|
3267
|
+
}
|
|
3268
|
+
const requirements = ordered
|
|
3269
|
+
.filter((declaration) => declaration.requirement)
|
|
3270
|
+
.map((declaration) => declaration.requirement);
|
|
3271
|
+
const result = {
|
|
3272
|
+
engine: exact?.engine || "ruby",
|
|
3273
|
+
requirements,
|
|
3274
|
+
conflicts: [],
|
|
3275
|
+
};
|
|
3276
|
+
if (exact) {
|
|
3277
|
+
for (const key of [
|
|
3278
|
+
"version",
|
|
3279
|
+
"patchlevel",
|
|
3280
|
+
"prerelease",
|
|
3281
|
+
"rubyVersion",
|
|
3282
|
+
"source",
|
|
3283
|
+
]) {
|
|
3284
|
+
if (exact[key] !== undefined) {
|
|
3285
|
+
result[key] = exact[key];
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
for (const other of ordered) {
|
|
3289
|
+
if (
|
|
3290
|
+
other !== exact &&
|
|
3291
|
+
other !== lockedPrerelease &&
|
|
3292
|
+
other.version &&
|
|
3293
|
+
(other.engine !== exact.engine || other.version !== exact.version)
|
|
3294
|
+
) {
|
|
3295
|
+
result.conflicts.push(
|
|
3296
|
+
`${other.source}: ${other.engine} ${other.version}`,
|
|
3297
|
+
);
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
return result;
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
/**
|
|
3305
|
+
* Describe the Ruby runtime of a project as one external `platform`
|
|
2866
3306
|
* component, and make the components that declare a `required_ruby_version`
|
|
2867
3307
|
* depend on it (discussion 4409).
|
|
2868
3308
|
*
|
|
2869
|
-
*
|
|
2870
|
-
*
|
|
2871
|
-
*
|
|
2872
|
-
*
|
|
2873
|
-
*
|
|
2874
|
-
*
|
|
3309
|
+
* When the project pins a Ruby (Gemfile.lock `RUBY VERSION`, `.ruby-version`,
|
|
3310
|
+
* `.tool-versions`, mise or the Gemfile `ruby` directive), the component names
|
|
3311
|
+
* that version, `pkg:generic/ruby@3.3.6`, with the CPE a scanner matches
|
|
3312
|
+
* interpreter advisories by. The requirements of the gems then stay in the
|
|
3313
|
+
* `cdx:ruby:requiredVersionRange` property, since CycloneDX allows a
|
|
3314
|
+
* `versionRange` only on a component without a version.
|
|
3315
|
+
*
|
|
3316
|
+
* Without a pin, the component stands for the Ruby the bundle as a whole runs
|
|
3317
|
+
* on, so its `versionRange` is the intersection of every requirement that
|
|
3318
|
+
* could be read, in the `vers` syntax CycloneDX mandates for the field. Each
|
|
3319
|
+
* component's own requirement stays in its `cdx:gem:rubyVersionSpecifiers`
|
|
3320
|
+
* property. One runtime component per distinct requirement would describe the
|
|
3321
|
+
* same interpreter many times over: a modest bundle spells `>= 2.x` a dozen
|
|
3322
|
+
* ways.
|
|
2875
3323
|
*
|
|
2876
3324
|
* The type is `platform`, the CycloneDX type for a runtime environment that
|
|
2877
3325
|
* interprets software, and the one cdxgen gives the Ruby it finds in the
|
|
2878
|
-
* build environment.
|
|
3326
|
+
* build environment. A range is not a version, so an unpinned purl names none.
|
|
2879
3327
|
*
|
|
2880
|
-
* `isExternal` and `versionRange` are CycloneDX 1.7 fields
|
|
2881
|
-
*
|
|
2882
|
-
*
|
|
3328
|
+
* `isExternal` and `versionRange` are CycloneDX 1.7 fields. A pinned runtime
|
|
3329
|
+
* also carries the `cdx:ruby:isExternal` property, which says the interpreter
|
|
3330
|
+
* comes with the deployment environment in a BOM of an older spec; the caller
|
|
3331
|
+
* decides whether such a BOM should carry an unpinned runtime at all.
|
|
2883
3332
|
*
|
|
2884
3333
|
* @param {Array} pkgList Components
|
|
2885
3334
|
* @param {object} parentComponent The metadata.component, when the project is
|
|
2886
3335
|
* itself a gem
|
|
2887
3336
|
* @param {Array} dependencies Dependency edges
|
|
3337
|
+
* @param {object} [projectRuby] result of resolveProjectRuby
|
|
2888
3338
|
* @returns {{pkgList: Array, dependencies: Array}} Components and edges with
|
|
2889
3339
|
* the runtime component added
|
|
2890
3340
|
*/
|
|
@@ -2892,6 +3342,7 @@ export function addRubyRuntimeComponent(
|
|
|
2892
3342
|
pkgList,
|
|
2893
3343
|
parentComponent,
|
|
2894
3344
|
dependencies,
|
|
3345
|
+
projectRuby,
|
|
2895
3346
|
) {
|
|
2896
3347
|
const requirements = [];
|
|
2897
3348
|
const declaringRefs = new Set();
|
|
@@ -2908,29 +3359,85 @@ export function addRubyRuntimeComponent(
|
|
|
2908
3359
|
declaringRefs.add(component["bom-ref"]);
|
|
2909
3360
|
}
|
|
2910
3361
|
}
|
|
2911
|
-
|
|
3362
|
+
for (const requirement of projectRuby?.requirements || []) {
|
|
3363
|
+
if (rubyRequirementToVers([requirement]) !== undefined) {
|
|
3364
|
+
requirements.push(requirement);
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
const pinned = projectRuby?.version;
|
|
3368
|
+
if (!pinned && !requirements.length) {
|
|
2912
3369
|
return { pkgList, dependencies };
|
|
2913
3370
|
}
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
runtimeComponent.
|
|
3371
|
+
if (projectRuby && parentComponent?.["bom-ref"]) {
|
|
3372
|
+
declaringRefs.add(parentComponent["bom-ref"]);
|
|
3373
|
+
}
|
|
3374
|
+
const versionRange = requirements.length
|
|
3375
|
+
? rubyRequirementToVers(requirements)
|
|
3376
|
+
: undefined;
|
|
3377
|
+
let runtimeComponent;
|
|
3378
|
+
if (pinned) {
|
|
3379
|
+
runtimeComponent = createRubyRuntimeComponent(pinned, {
|
|
3380
|
+
engine: projectRuby.engine,
|
|
3381
|
+
// Bundler records no tag for a pre-release, so no CPE can name it
|
|
3382
|
+
withCpe: !projectRuby.prerelease,
|
|
3383
|
+
});
|
|
3384
|
+
runtimeComponent.scope = "required";
|
|
3385
|
+
runtimeComponent.isExternal = true;
|
|
3386
|
+
const properties = [
|
|
3387
|
+
{ name: "cdx:ruby:isExternal", value: "true" },
|
|
3388
|
+
{ name: "cdx:ruby:versionSource", value: projectRuby.source },
|
|
3389
|
+
];
|
|
3390
|
+
if (projectRuby.prerelease) {
|
|
3391
|
+
// Not the release of that number, and no tag says which pre-release
|
|
3392
|
+
properties.push({ name: "cdx:ruby:prerelease", value: "true" });
|
|
3393
|
+
}
|
|
3394
|
+
if (projectRuby.patchlevel !== undefined) {
|
|
3395
|
+
properties.push({
|
|
3396
|
+
name: "cdx:ruby:patchlevel",
|
|
3397
|
+
value: projectRuby.patchlevel,
|
|
3398
|
+
});
|
|
3399
|
+
}
|
|
3400
|
+
if (projectRuby.rubyVersion) {
|
|
3401
|
+
properties.push({
|
|
3402
|
+
name: "cdx:ruby:languageVersion",
|
|
3403
|
+
value: projectRuby.rubyVersion,
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
3406
|
+
if (versionRange) {
|
|
3407
|
+
properties.push({
|
|
3408
|
+
name: "cdx:ruby:requiredVersionRange",
|
|
3409
|
+
value: versionRange,
|
|
3410
|
+
});
|
|
3411
|
+
}
|
|
3412
|
+
if (projectRuby.conflicts?.length) {
|
|
3413
|
+
properties.push({
|
|
3414
|
+
name: "cdx:ruby:conflictingDeclarations",
|
|
3415
|
+
value: projectRuby.conflicts.join(", "),
|
|
3416
|
+
});
|
|
3417
|
+
}
|
|
3418
|
+
runtimeComponent.properties = properties;
|
|
2928
3419
|
} else {
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
3420
|
+
const runtimeRef = genericPurl("ruby");
|
|
3421
|
+
runtimeComponent = {
|
|
3422
|
+
type: "platform",
|
|
3423
|
+
name: "ruby",
|
|
3424
|
+
scope: "required",
|
|
3425
|
+
// The interpreter comes with the deployment environment, not with the
|
|
3426
|
+
// product the BOM describes
|
|
3427
|
+
isExternal: true,
|
|
3428
|
+
purl: runtimeRef,
|
|
3429
|
+
"bom-ref": runtimeRef,
|
|
3430
|
+
};
|
|
3431
|
+
if (versionRange) {
|
|
3432
|
+
runtimeComponent.versionRange = versionRange;
|
|
3433
|
+
} else {
|
|
3434
|
+
thoughtLog(
|
|
3435
|
+
"The Ruby version requirements of the gems exclude each other, so the Ruby runtime component carries no version range.",
|
|
3436
|
+
{ requirements },
|
|
3437
|
+
);
|
|
3438
|
+
}
|
|
2933
3439
|
}
|
|
3440
|
+
const runtimeRef = runtimeComponent["bom-ref"];
|
|
2934
3441
|
const describedRefs = new Set(dependencies.map((d) => d.ref));
|
|
2935
3442
|
const outDependencies = dependencies.map((d) =>
|
|
2936
3443
|
declaringRefs.has(d.ref)
|
package/lib/ecosystems/rusi.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "../core/pluginRun.js";
|
|
17
17
|
import { isProjectToolingAllowed } from "../core/projectTooling.js";
|
|
18
18
|
import { applyAlgorithmProperties } from "../inventory/cryptoAlgorithmFamily.js";
|
|
19
|
+
import { occurrenceLocationKey } from "../inventory/occurrenceKey.js";
|
|
19
20
|
import { resolvePluginBinary } from "../inventory/plugins.js";
|
|
20
21
|
|
|
21
22
|
const RUST_LANGUAGES = new Set(["rust", "rs", "rust-lang"]);
|
|
@@ -67,10 +68,7 @@ function positionLocation(position) {
|
|
|
67
68
|
if (!position?.filename) {
|
|
68
69
|
return undefined;
|
|
69
70
|
}
|
|
70
|
-
|
|
71
|
-
return `${position.filename}#${position.line}`;
|
|
72
|
-
}
|
|
73
|
-
return position.filename;
|
|
71
|
+
return occurrenceLocationKey(position.filename, position.line);
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
function purlWithoutVersion(purl) {
|
|
@@ -7,6 +7,7 @@ import { getAllFiles, safeExistsSync, safeSpawnSync } from "../core/fs.js";
|
|
|
7
7
|
import { isWin } from "../core/paths.js";
|
|
8
8
|
import { isProjectToolingAllowed } from "../core/projectTooling.js";
|
|
9
9
|
import { noteBuildToolRateLimit } from "../inventory/buildToolRateLimit.js";
|
|
10
|
+
import { coursierMirrorEnv } from "../inventory/mavenCentralMirror.js";
|
|
10
11
|
import { parseScalaArtifact } from "../inventory/scalaCoords.js";
|
|
11
12
|
import { completeComponent } from "./parsers-jvm.js";
|
|
12
13
|
|
|
@@ -297,6 +298,7 @@ export function collectScalaCliComponents(dirPath, options = {}) {
|
|
|
297
298
|
shell: isWin,
|
|
298
299
|
maxBuffer: 100 * 1024 * 1024,
|
|
299
300
|
timeout: 600_000,
|
|
301
|
+
env: { ...process.env, ...coursierMirrorEnv() },
|
|
300
302
|
});
|
|
301
303
|
// scala-cli resolves through Coursier, so the class path fails with its
|
|
302
304
|
// downloader message when the repository rate limits the machine.
|