@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
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// Bounded Node.js build-version reader for unpackaged `node` binaries.
|
|
2
|
+
//
|
|
3
|
+
// The Node.js the Docker Official images, the release tarballs, nvm, fnm and
|
|
4
|
+
// volta install is not owned by any package manager, so a BOM sees it only as
|
|
5
|
+
// a file. Its version decides whether the runtime is affected by advisories
|
|
6
|
+
// such as CVE-2026-111497 (fixed in 22.23.4, 24.22.1 and 26.12.1).
|
|
7
|
+
//
|
|
8
|
+
// Two markers are compiled into the binary:
|
|
9
|
+
// - the release URLs, `https://nodejs.org/download/<channel>/v<version>/`,
|
|
10
|
+
// which a build configured with release URLs (every nodejs.org build)
|
|
11
|
+
// carries for process.release.sourceUrl and headersUrl
|
|
12
|
+
// https://github.com/nodejs/node/blob/v24.22.0/src/node_metadata.cc#L191-L197
|
|
13
|
+
// - `node.js/v<version>`, NUL-terminated, the inspector's /json/version
|
|
14
|
+
// Browser string, which every build with the inspector carries; it is the
|
|
15
|
+
// fallback for a build without release URLs.
|
|
16
|
+
// https://github.com/nodejs/node/blob/v24.22.0/src/inspector_socket_server.cc#L117
|
|
17
|
+
//
|
|
18
|
+
// process.versions.brotli is not a usable signal: Node.js backports the
|
|
19
|
+
// decoder fix without changing it (24.22.1 still reports 1.2.0). The decoder
|
|
20
|
+
// state is read separately, by brotliDecoder.js.
|
|
21
|
+
|
|
22
|
+
import { basename } from "node:path";
|
|
23
|
+
|
|
24
|
+
import { scanFileMarkers } from "../core/boundedFile.js";
|
|
25
|
+
import { applyPurl, tryBuildPurl } from "./purl.js";
|
|
26
|
+
|
|
27
|
+
const RELEASE_URL_MARKER = Buffer.from("https://nodejs.org/download/");
|
|
28
|
+
const USER_AGENT_MARKER = Buffer.from("node.js/v");
|
|
29
|
+
const MAX_VERSION_LENGTH = 64;
|
|
30
|
+
const VERSION_RE = /^(\d+\.\d+\.\d+)(?:-([0-9A-Za-z][0-9A-Za-z.]*))?$/;
|
|
31
|
+
const CHANNELS = new Set(["release", "rc", "nightly", "test", "v8-canary"]);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The most node-named files one scan opens in search of a build version.
|
|
35
|
+
*
|
|
36
|
+
* @type {number}
|
|
37
|
+
*/
|
|
38
|
+
export const MAX_NODE_PROBES = 64;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Whether a file name is one the Node.js runtime is installed under.
|
|
42
|
+
*
|
|
43
|
+
* @param {string} fileName basename or path of the candidate
|
|
44
|
+
* @returns {boolean} true for `node`, `nodejs` and `node.exe`
|
|
45
|
+
*/
|
|
46
|
+
export function isNodeBinaryName(fileName) {
|
|
47
|
+
if (typeof fileName !== "string" || !fileName) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const name = basename(fileName.replaceAll("\\", "/"));
|
|
51
|
+
return name === "node" || name === "nodejs" || name === "node.exe";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Parse a Node.js version in the grammar the release tooling produces:
|
|
56
|
+
* `24.22.1`, `25.0.0-rc.1`, `26.0.0-nightly20260301abcdef`.
|
|
57
|
+
*
|
|
58
|
+
* @param {string} text candidate version, without the leading `v`
|
|
59
|
+
* @returns {string|undefined} the version, or undefined
|
|
60
|
+
*/
|
|
61
|
+
export function parseNodeVersion(text) {
|
|
62
|
+
if (typeof text !== "string" || !text || text.length > MAX_VERSION_LENGTH) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return VERSION_RE.test(text) ? text : undefined;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function versionFromReleaseUrl(after) {
|
|
69
|
+
// <channel>/v<version>/...
|
|
70
|
+
const text = after.toString("latin1");
|
|
71
|
+
const slash = text.indexOf("/");
|
|
72
|
+
if (slash <= 0) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
const channel = text.slice(0, slash);
|
|
76
|
+
if (!CHANNELS.has(channel) || text[slash + 1] !== "v") {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const end = text.indexOf("/", slash + 2);
|
|
80
|
+
if (end === -1) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const version = parseNodeVersion(text.slice(slash + 2, end));
|
|
84
|
+
return version ? { version, channel } : undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function versionFromUserAgent(after) {
|
|
88
|
+
const end = after.indexOf(0);
|
|
89
|
+
if (end <= 0) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
return parseNodeVersion(after.toString("latin1", 0, end));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Read the Node.js version a `node` binary was built as.
|
|
97
|
+
*
|
|
98
|
+
* @param {string} absPath absolute path of the binary
|
|
99
|
+
* @param {string|undefined} rootDir extracted root, when the file came from one
|
|
100
|
+
* @returns {{version: string, source: string, channel?: string}|undefined}
|
|
101
|
+
* source is `release-url` or `binary`
|
|
102
|
+
*/
|
|
103
|
+
export function readNodeBuildVersion(absPath, rootDir) {
|
|
104
|
+
const scan = scanFileMarkers(
|
|
105
|
+
absPath,
|
|
106
|
+
rootDir,
|
|
107
|
+
[RELEASE_URL_MARKER, USER_AGENT_MARKER],
|
|
108
|
+
{ contextBytes: MAX_VERSION_LENGTH + 32, maxHits: 8 },
|
|
109
|
+
);
|
|
110
|
+
if (!scan || scan.skipped) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
const [releaseHits, userAgentHits] = scan.hits;
|
|
114
|
+
const fromBinary = userAgentHits
|
|
115
|
+
.map((hit) => versionFromUserAgent(hit.after))
|
|
116
|
+
.find(Boolean);
|
|
117
|
+
for (const hit of releaseHits) {
|
|
118
|
+
const release = versionFromReleaseUrl(hit.after);
|
|
119
|
+
// The headers URL names the release a binary was published as. A binary
|
|
120
|
+
// whose own version string disagrees is not that release, so the URL is
|
|
121
|
+
// used only when the two agree or the version string is missing.
|
|
122
|
+
if (release && (!fromBinary || fromBinary === release.version)) {
|
|
123
|
+
return {
|
|
124
|
+
version: release.version,
|
|
125
|
+
source: "release-url",
|
|
126
|
+
channel: release.channel,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return fromBinary ? { version: fromBinary, source: "binary" } : undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* The CPE that lets a downstream scanner match a Node.js version. NVD names the
|
|
135
|
+
* product node.js and keeps a pre-release in the update field.
|
|
136
|
+
*
|
|
137
|
+
* @param {string} version Node.js version
|
|
138
|
+
* @returns {string} CPE 2.3 string
|
|
139
|
+
*/
|
|
140
|
+
export function nodeCpe(version) {
|
|
141
|
+
const match = VERSION_RE.exec(version || "");
|
|
142
|
+
if (!match) {
|
|
143
|
+
return `cpe:2.3:a:nodejs:node.js:${version}:*:*:*:*:*:*:*`;
|
|
144
|
+
}
|
|
145
|
+
const update = match[2] ? match[2].replaceAll(".", "").toLowerCase() : "*";
|
|
146
|
+
return `cpe:2.3:a:nodejs:node.js:${match[1]}:${update}:*:*:*:*:*:*`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* A Node.js runtime is one `platform` component per distinct version, like the
|
|
151
|
+
* PHP and Go stdlib components. Its identity is `pkg:generic/node`: it is only
|
|
152
|
+
* used where no package manager owns the runtime.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} version Node.js version
|
|
155
|
+
* @returns {Object} component with `purl`, `bom-ref` and `cpe`
|
|
156
|
+
*/
|
|
157
|
+
export function createNodeRuntimeComponent(version) {
|
|
158
|
+
return applyPurl(
|
|
159
|
+
{ type: "platform", name: "node", version, cpe: nodeCpe(version) },
|
|
160
|
+
tryBuildPurl({ type: "generic", name: "node", version }),
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The properties a node file component carries once its build is known.
|
|
166
|
+
*
|
|
167
|
+
* @param {{version: string, source: string, channel?: string}} build result of readNodeBuildVersion
|
|
168
|
+
* @returns {{name: string, value: string}[]} properties to append
|
|
169
|
+
*/
|
|
170
|
+
export function nodeBuildProperties(build) {
|
|
171
|
+
const properties = [
|
|
172
|
+
{ name: "cdx:node:buildVersion", value: build.version },
|
|
173
|
+
{ name: "cdx:node:buildVersionSource", value: build.source },
|
|
174
|
+
];
|
|
175
|
+
if (build.channel) {
|
|
176
|
+
properties.push({ name: "cdx:node:releaseChannel", value: build.channel });
|
|
177
|
+
}
|
|
178
|
+
return properties;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Start collecting the runtime components and edges of one scan.
|
|
183
|
+
*
|
|
184
|
+
* @returns {{runtimeComponents: Object[], dependencies: Object[], runtimeRefs: Set<string>}}
|
|
185
|
+
*/
|
|
186
|
+
export function createNodeRuntimeInventory() {
|
|
187
|
+
return { runtimeComponents: [], dependencies: [], runtimeRefs: new Set() };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Tag a node file component with its build facts and link it to the runtime
|
|
192
|
+
* component of its version, creating that component on first use. Mutates the
|
|
193
|
+
* component in place.
|
|
194
|
+
*
|
|
195
|
+
* @param {{runtimeComponents: Object[], dependencies: Object[], runtimeRefs: Set<string>}} inventory
|
|
196
|
+
* accumulator from createNodeRuntimeInventory
|
|
197
|
+
* @param {Object} component file component, with a `properties` array
|
|
198
|
+
* @param {{version: string, source: string, channel?: string}} build result of readNodeBuildVersion
|
|
199
|
+
*/
|
|
200
|
+
export function attachNodeBuild(inventory, component, build) {
|
|
201
|
+
component.properties.push(...nodeBuildProperties(build));
|
|
202
|
+
const runtime = createNodeRuntimeComponent(build.version);
|
|
203
|
+
const runtimeRef = runtime["bom-ref"];
|
|
204
|
+
if (!runtimeRef) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (!inventory.runtimeRefs.has(runtimeRef)) {
|
|
208
|
+
inventory.runtimeRefs.add(runtimeRef);
|
|
209
|
+
inventory.runtimeComponents.push(runtime);
|
|
210
|
+
inventory.dependencies.push({ ref: runtimeRef, dependsOn: [] });
|
|
211
|
+
}
|
|
212
|
+
if (component["bom-ref"]) {
|
|
213
|
+
inventory.dependencies.push({
|
|
214
|
+
ref: component["bom-ref"],
|
|
215
|
+
dependsOn: [runtimeRef],
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// Bounded, read-only probe for the Node.js no package manager owns on a live
|
|
2
|
+
// host, for `-t os` / obom. The release tarballs, the nodejs.org installer and
|
|
3
|
+
// the version managers (nvm, fnm, volta, asdf, mise, n) put Node.js where no
|
|
4
|
+
// package database records it, so an OBOM sees neither the runtime nor the
|
|
5
|
+
// Brotli decoder compiled into it.
|
|
6
|
+
//
|
|
7
|
+
// Candidates come from fixed directories and from each version manager's
|
|
8
|
+
// tree under the home directories, one wildcard level at a time, never from a
|
|
9
|
+
// walk of the file system. The ownership rules, caps and degradations are the
|
|
10
|
+
// shared host-runtime probe's.
|
|
11
|
+
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
isDryRun,
|
|
16
|
+
readEnvironmentVariable,
|
|
17
|
+
recordActivity,
|
|
18
|
+
} from "../core/activity.js";
|
|
19
|
+
import { recordDegradation } from "../core/buildLedger.js";
|
|
20
|
+
import {
|
|
21
|
+
attachBrotliDecoder,
|
|
22
|
+
createBrotliInventory,
|
|
23
|
+
finishBrotliInventory,
|
|
24
|
+
readBrotliDecoder,
|
|
25
|
+
} from "./brotliDecoder.js";
|
|
26
|
+
import {
|
|
27
|
+
isDirectory,
|
|
28
|
+
listDirectory,
|
|
29
|
+
probeHostRuntime,
|
|
30
|
+
} from "./hostRuntimeProbe.js";
|
|
31
|
+
import {
|
|
32
|
+
attachNodeBuild,
|
|
33
|
+
createNodeRuntimeInventory,
|
|
34
|
+
isNodeBinaryName,
|
|
35
|
+
MAX_NODE_PROBES,
|
|
36
|
+
readNodeBuildVersion,
|
|
37
|
+
} from "./nodeBuildInfo.js";
|
|
38
|
+
|
|
39
|
+
// The most directories one wildcard pattern may expand to.
|
|
40
|
+
const MAX_EXPANDED_DIRECTORIES = 256;
|
|
41
|
+
|
|
42
|
+
// Relative to the root.
|
|
43
|
+
const POSIX_DIRECTORIES = {
|
|
44
|
+
linux: ["usr/local/bin", "opt/*/bin", "usr/local/n/versions/node/*/bin"],
|
|
45
|
+
darwin: ["usr/local/bin", "opt/homebrew/bin", "opt/*/bin"],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Relative to a home directory.
|
|
49
|
+
const VERSION_MANAGER_DIRECTORIES = [
|
|
50
|
+
".nvm/versions/node/*/bin",
|
|
51
|
+
".local/share/fnm/node-versions/*/installation/bin",
|
|
52
|
+
".fnm/node-versions/*/installation/bin",
|
|
53
|
+
"Library/Application Support/fnm/node-versions/*/installation/bin",
|
|
54
|
+
".volta/tools/image/node/*/bin",
|
|
55
|
+
".asdf/installs/nodejs/*/bin",
|
|
56
|
+
".local/share/mise/installs/node/*/bin",
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
const HOME_PARENTS = {
|
|
60
|
+
linux: ["home"],
|
|
61
|
+
darwin: ["Users"],
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Expand a relative directory pattern whose `*` segments match one directory
|
|
66
|
+
* name each.
|
|
67
|
+
*
|
|
68
|
+
* @param {string} base absolute directory the pattern hangs off
|
|
69
|
+
* @param {string} pattern `/`-separated relative pattern
|
|
70
|
+
* @returns {string[]} existing directories, at most MAX_EXPANDED_DIRECTORIES
|
|
71
|
+
*/
|
|
72
|
+
function expandDirectories(base, pattern) {
|
|
73
|
+
let current = [base];
|
|
74
|
+
for (const segment of pattern.split("/")) {
|
|
75
|
+
const next = [];
|
|
76
|
+
for (const directory of current) {
|
|
77
|
+
if (segment !== "*") {
|
|
78
|
+
next.push(join(directory, segment));
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
for (const name of listDirectory(directory)) {
|
|
82
|
+
const child = join(directory, name);
|
|
83
|
+
if (isDirectory(child)) {
|
|
84
|
+
next.push(child);
|
|
85
|
+
}
|
|
86
|
+
if (next.length >= MAX_EXPANDED_DIRECTORIES) {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
current = next.slice(0, MAX_EXPANDED_DIRECTORIES);
|
|
92
|
+
}
|
|
93
|
+
return current.filter(isDirectory);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function homeDirectories(context) {
|
|
97
|
+
const { rootPath, platform } = context;
|
|
98
|
+
const homes = [];
|
|
99
|
+
if (platform === "linux") {
|
|
100
|
+
homes.push(join(rootPath, "root"));
|
|
101
|
+
}
|
|
102
|
+
for (const parent of HOME_PARENTS[platform] || []) {
|
|
103
|
+
for (const name of listDirectory(join(rootPath, parent))) {
|
|
104
|
+
const home = join(rootPath, parent, name);
|
|
105
|
+
if (isDirectory(home)) {
|
|
106
|
+
homes.push(home);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return homes.slice(0, MAX_EXPANDED_DIRECTORIES);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Where the Node.js MSI installs, by itself or for Chocolatey's nodejs.install.
|
|
114
|
+
function windowsInstallDirectory(context) {
|
|
115
|
+
const programFiles =
|
|
116
|
+
context.readEnv("ProgramFiles") || join(context.rootPath, "Program Files");
|
|
117
|
+
return join(programFiles, "nodejs");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function candidateDirectories(context) {
|
|
121
|
+
const { rootPath, platform } = context;
|
|
122
|
+
const directories = [];
|
|
123
|
+
if (platform === "win32") {
|
|
124
|
+
directories.push({ directory: windowsInstallDirectory(context) });
|
|
125
|
+
const appData = context.readEnv("APPDATA");
|
|
126
|
+
if (appData) {
|
|
127
|
+
for (const directory of expandDirectories(appData, "nvm/*")) {
|
|
128
|
+
directories.push({ directory });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return directories;
|
|
132
|
+
}
|
|
133
|
+
for (const pattern of POSIX_DIRECTORIES[platform] || []) {
|
|
134
|
+
for (const directory of expandDirectories(rootPath, pattern)) {
|
|
135
|
+
directories.push({ directory });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
for (const home of homeDirectories(context)) {
|
|
139
|
+
for (const pattern of VERSION_MANAGER_DIRECTORIES) {
|
|
140
|
+
for (const directory of expandDirectories(home, pattern)) {
|
|
141
|
+
directories.push({ directory });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return directories;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function readBuild(context, candidate) {
|
|
149
|
+
const node = readNodeBuildVersion(candidate.real, context.realRoot);
|
|
150
|
+
if (!node) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
return { node, brotli: readBrotliDecoder(candidate.real, context.realRoot) };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Look for Node.js no package manager owns on the host. Components come back
|
|
158
|
+
* only for the files nothing owns: a `file` component for each `node` binary
|
|
159
|
+
* with the cdx:node and cdx:brotli properties, one `platform` component per
|
|
160
|
+
* Node.js version with its CPE, and the brotli component when a binary embeds
|
|
161
|
+
* a decoder.
|
|
162
|
+
*
|
|
163
|
+
* @param {Object} [options] probe options, as probeHostPhp takes them
|
|
164
|
+
* @returns {{components: Object[], dependencies: Object[]}}
|
|
165
|
+
*/
|
|
166
|
+
export function probeHostNode(options = {}) {
|
|
167
|
+
return probeHostRuntime(options, {
|
|
168
|
+
label: "Node.js",
|
|
169
|
+
ecosystem: "npm",
|
|
170
|
+
capability: "node-host-probe",
|
|
171
|
+
remediationId: "npm.host-probe.package-db-unreadable",
|
|
172
|
+
maxProbes: MAX_NODE_PROBES,
|
|
173
|
+
chocolateyPackages: ["nodejs", "nodejs-lts", "nodejs.install"],
|
|
174
|
+
chocolateyDirectories: (context) => [windowsInstallDirectory(context)],
|
|
175
|
+
directories: candidateDirectories,
|
|
176
|
+
classify: (name) => (isNodeBinaryName(name) ? "node" : undefined),
|
|
177
|
+
readBuild,
|
|
178
|
+
createInventory: () => ({
|
|
179
|
+
node: createNodeRuntimeInventory(),
|
|
180
|
+
brotli: createBrotliInventory(),
|
|
181
|
+
}),
|
|
182
|
+
attach: (inventory, component, build) => {
|
|
183
|
+
attachNodeBuild(inventory.node, component, build.node);
|
|
184
|
+
if (build.brotli) {
|
|
185
|
+
attachBrotliDecoder(inventory.brotli, component, build.brotli);
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
finish: (inventory) => {
|
|
189
|
+
const brotli = finishBrotliInventory(inventory.brotli);
|
|
190
|
+
return {
|
|
191
|
+
components: [...inventory.node.runtimeComponents, ...brotli.components],
|
|
192
|
+
dependencies: [...inventory.node.dependencies, ...brotli.dependencies],
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
hooks: {
|
|
196
|
+
isDryRun,
|
|
197
|
+
readEnvironmentVariable,
|
|
198
|
+
recordActivity,
|
|
199
|
+
recordDegradation,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The key of a place in a purl's occurrence set (`purlLocationMap`).
|
|
3
|
+
*
|
|
4
|
+
* Every location that enters an occurrence set is keyed by this function,
|
|
5
|
+
* whatever evidence source added it: the seeding from the input BOM
|
|
6
|
+
* (`initFromSbom`), the atom `usages` and `callsites` slices, the golem, rusi,
|
|
7
|
+
* kosi, dosai and scalasem reports, the C include attribution and the Swift
|
|
8
|
+
* semantics slices. Backslashes become `/`, so a place spelled with `\` in the
|
|
9
|
+
* input BOM (Windows cdxgen output) and `/` in a slice is one occurrence, not
|
|
10
|
+
* two (issue 4726). The path is otherwise left as spelled: no resolving, no
|
|
11
|
+
* case folding, no stripping of a leading `./`.
|
|
12
|
+
*
|
|
13
|
+
* A place a line already names is keyed `file#line`; a place a callsites
|
|
14
|
+
* record names down to its column (counted from 0, as atom writes it) is keyed
|
|
15
|
+
* `file:line:offset`, so two use
|
|
16
|
+
* sites on one line are two occurrences. An occurrence with only `location`
|
|
17
|
+
* and `line` names the line as a whole: it is the same place as any use site
|
|
18
|
+
* that line carries, and it is kept as an occurrence of its own only while no
|
|
19
|
+
* `file:line:offset` key of that line exists (the writer drops the line-only
|
|
20
|
+
* key then, see `dropSubsumedOccurrenceKeys`). That rule is what keeps a
|
|
21
|
+
* re-run of evinse over its own output at the same occurrences: the first run
|
|
22
|
+
* writes the `file:line:offset` keys, and the second run seeds and re-adds
|
|
23
|
+
* exactly those.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} location File path or other location text
|
|
26
|
+
* @param {number} [line] Line number; not a positive number means the location names no line
|
|
27
|
+
* @param {number} [offset] Column within the line, counted from 0 as atom writes it; a value that is not an integer of 0 or more (atom writes -1 for an unknown column) means the place is the line
|
|
28
|
+
* @returns {string|undefined} Key in the `file:line:offset`, `file#line` or plain `file` shape; undefined when the location is empty
|
|
29
|
+
*/
|
|
30
|
+
export function occurrenceLocationKey(location, line, offset) {
|
|
31
|
+
const normalized = `${location ?? ""}`.trim().replaceAll("\\", "/");
|
|
32
|
+
if (!normalized) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
if (!(line > 0)) {
|
|
36
|
+
return normalized;
|
|
37
|
+
}
|
|
38
|
+
return Number.isInteger(offset) && offset >= 0
|
|
39
|
+
? `${normalized}:${line}:${offset}`
|
|
40
|
+
: `${normalized}#${line}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Drop the occurrence keys a use-site key subsumes.
|
|
45
|
+
*
|
|
46
|
+
* A `file:line:offset` key names a use site on a line; the line-only
|
|
47
|
+
* `file#line` key of the same line names no place of its own any more, so it
|
|
48
|
+
* is removed rather than counted beside the use sites (issue 4726: an
|
|
49
|
+
* occurrence seeded from an input BOM with only `location` and `line` is the
|
|
50
|
+
* same place as a callsites occurrence at that line).
|
|
51
|
+
*
|
|
52
|
+
* @param {string[]} keys Occurrence-set keys
|
|
53
|
+
* @returns {string[]} The keys without the subsumed line-only entries
|
|
54
|
+
*/
|
|
55
|
+
export function dropSubsumedOccurrenceKeys(keys) {
|
|
56
|
+
const linesWithOffset = new Set();
|
|
57
|
+
for (const key of keys) {
|
|
58
|
+
const withOffset = /^(.*):(\d+):(\d+)$/.exec(key);
|
|
59
|
+
if (withOffset) {
|
|
60
|
+
linesWithOffset.add(`${withOffset[1]}#${withOffset[2]}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!linesWithOffset.size) {
|
|
64
|
+
return keys;
|
|
65
|
+
}
|
|
66
|
+
return keys.filter((key) => {
|
|
67
|
+
const lineOnly = /^(.*)#(\d+)$/.exec(key);
|
|
68
|
+
return !(lineOnly && linesWithOffset.has(`${lineOnly[1]}#${lineOnly[2]}`));
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The location part of an occurrence-set key: `src/a.js` for `src/a.js#3`,
|
|
74
|
+
* `src/a.js:3:14` and `src/a.js` alike.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} key Key made by `occurrenceLocationKey`
|
|
77
|
+
* @returns {string} The location the key names
|
|
78
|
+
*/
|
|
79
|
+
export function occurrenceKeyLocation(key) {
|
|
80
|
+
const text = `${key ?? ""}`;
|
|
81
|
+
const withOffset = /^(.*):(\d+):(\d+)$/.exec(text);
|
|
82
|
+
if (withOffset) {
|
|
83
|
+
return withOffset[1];
|
|
84
|
+
}
|
|
85
|
+
const hash = text.lastIndexOf("#");
|
|
86
|
+
if (hash > 0 && /^\d+$/.test(text.slice(hash + 1))) {
|
|
87
|
+
return text.slice(0, hash);
|
|
88
|
+
}
|
|
89
|
+
return text;
|
|
90
|
+
}
|
|
@@ -493,3 +493,185 @@ function collectAllLdConfs(basePath, ldConf, allLdConfDirs, libPaths) {
|
|
|
493
493
|
}
|
|
494
494
|
}
|
|
495
495
|
}
|
|
496
|
+
|
|
497
|
+
// Native modules that language package managers install outside the library
|
|
498
|
+
// directories the loader searches: CPython and PyPy extension modules, PHP
|
|
499
|
+
// extensions, Ruby gem extensions, Node.js addons, and the native half of a
|
|
500
|
+
// .NET runtime. A Brotli decoder compiled into one of them is invisible unless
|
|
501
|
+
// the file is read.
|
|
502
|
+
const NATIVE_EXTENSION_GLOBS = [
|
|
503
|
+
"**/site-packages/**/*.{so,pyd}",
|
|
504
|
+
"**/dist-packages/**/*.so",
|
|
505
|
+
"**/lib/php/**/*.so",
|
|
506
|
+
"**/lib/php*/modules/*.so",
|
|
507
|
+
"**/php*/ext/php_*.dll",
|
|
508
|
+
"**/gems/*/lib/**/*.{so,bundle}",
|
|
509
|
+
"**/gems/*/extensions/**/*.{so,bundle}",
|
|
510
|
+
"**/bundle/extensions/**/*.{so,bundle}",
|
|
511
|
+
"**/node_modules/**/*.node",
|
|
512
|
+
"**/dotnet/shared/*/*/*.so",
|
|
513
|
+
"**/.dotnet/shared/*/*/*.so",
|
|
514
|
+
// Of a Windows runtime's many DLLs, only this one is native and holds the
|
|
515
|
+
// decoder.
|
|
516
|
+
"**/dotnet/shared/*/*/System.IO.Compression.Native.dll",
|
|
517
|
+
];
|
|
518
|
+
const NATIVE_EXTENSION_IGNORES = ["proc/**", "sys/**", "dev/**"];
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* The most native extension candidates one scan returns.
|
|
522
|
+
*
|
|
523
|
+
* @type {number}
|
|
524
|
+
*/
|
|
525
|
+
export const MAX_NATIVE_EXTENSIONS = 4096;
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Collect native extension modules under a root file system that the library
|
|
529
|
+
* collector does not see, leaving out paths a package database owns and paths
|
|
530
|
+
* already collected. Symlinks are not followed, so a link pointing out of the
|
|
531
|
+
* root is never listed.
|
|
532
|
+
*
|
|
533
|
+
* @param {string} basePath extracted root file system
|
|
534
|
+
* @param {string[]} [excludePaths] root-relative paths to leave out
|
|
535
|
+
* @returns {string[]} root-relative paths, sorted, capped at MAX_NATIVE_EXTENSIONS
|
|
536
|
+
*/
|
|
537
|
+
export function collectNativeExtensions(basePath, excludePaths = []) {
|
|
538
|
+
if (!basePath) {
|
|
539
|
+
return [];
|
|
540
|
+
}
|
|
541
|
+
const excluded = new Set(
|
|
542
|
+
(excludePaths || []).map((f) => f.replace(/^\/+/, "").replace(/\\/g, "/")),
|
|
543
|
+
);
|
|
544
|
+
let files = [];
|
|
545
|
+
try {
|
|
546
|
+
files = globSync(NATIVE_EXTENSION_GLOBS, {
|
|
547
|
+
cwd: basePath,
|
|
548
|
+
absolute: false,
|
|
549
|
+
nodir: true,
|
|
550
|
+
dot: true,
|
|
551
|
+
follow: false,
|
|
552
|
+
ignore: NATIVE_EXTENSION_IGNORES,
|
|
553
|
+
});
|
|
554
|
+
} catch (_err) {
|
|
555
|
+
return [];
|
|
556
|
+
}
|
|
557
|
+
const result = new Set();
|
|
558
|
+
for (const file of files) {
|
|
559
|
+
const normalized = file.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
560
|
+
if (!excluded.has(normalized)) {
|
|
561
|
+
result.add(normalized);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return Array.from(result).sort().slice(0, MAX_NATIVE_EXTENSIONS);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const OS_PACKAGE_PURL_PREFIXES = [
|
|
568
|
+
"pkg:deb/",
|
|
569
|
+
"pkg:apk/",
|
|
570
|
+
"pkg:rpm/",
|
|
571
|
+
"pkg:alpm/",
|
|
572
|
+
"pkg:qpkg/",
|
|
573
|
+
"pkg:generic/",
|
|
574
|
+
];
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Whether a source file is the installation record of a language package,
|
|
578
|
+
* the file a package manager writes when it installs the package: dist-info
|
|
579
|
+
* or egg-info metadata, an installed gemspec, a package.json inside
|
|
580
|
+
* node_modules, or a jar. A lock file or manifest only names packages, so an
|
|
581
|
+
* OS package owning one says nothing about who installed them.
|
|
582
|
+
*
|
|
583
|
+
* @param {string} filePath root-relative path with forward slashes
|
|
584
|
+
* @returns {boolean}
|
|
585
|
+
*/
|
|
586
|
+
function isInstallRecord(filePath) {
|
|
587
|
+
const parts = filePath.split("/");
|
|
588
|
+
const name = parts.at(-1) || "";
|
|
589
|
+
const parent = parts.at(-2) || "";
|
|
590
|
+
if (parent.endsWith(".dist-info") || parent.endsWith(".egg-info")) {
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
if (name.endsWith(".egg-info") || name.endsWith(".jar")) {
|
|
594
|
+
return true;
|
|
595
|
+
}
|
|
596
|
+
if (name.endsWith(".gemspec") && parts.includes("specifications")) {
|
|
597
|
+
return true;
|
|
598
|
+
}
|
|
599
|
+
return name === "package.json" && parts.includes("node_modules");
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Mark language packages that an OS package installed. Alpine's py3-brotli
|
|
604
|
+
* ships a Brotli-1.1.0.dist-info that a Python scan reports as
|
|
605
|
+
* pkg:pypi/brotli@1.1.0, but a distro fixes it by backporting under the same
|
|
606
|
+
* upstream version, so a PyPI advisory range keeps matching after the fix. The
|
|
607
|
+
* `cdx:os:installedBy` property names the OS package that owns the
|
|
608
|
+
* installation record, so a consumer can judge the component by that package
|
|
609
|
+
* instead.
|
|
610
|
+
*
|
|
611
|
+
* A component is marked only when every installation record it was read from
|
|
612
|
+
* belongs to an OS package: a copy that pip put in a virtual environment
|
|
613
|
+
* beside the distro's is not the distro's to fix. Run it after duplicates
|
|
614
|
+
* merge, so that a merged component carries all of its records.
|
|
615
|
+
*
|
|
616
|
+
* @param {Object[]} components BOM components, mutated in place
|
|
617
|
+
* @param {Map<string, string>|undefined} ownerByPath root-relative file path to
|
|
618
|
+
* owning OS package bom-ref
|
|
619
|
+
* @param {string} [rootDir] extracted root, stripped from absolute source paths
|
|
620
|
+
* @returns {number} how many components were marked
|
|
621
|
+
*/
|
|
622
|
+
export function markOsInstalledLanguagePackages(
|
|
623
|
+
components,
|
|
624
|
+
ownerByPath,
|
|
625
|
+
rootDir,
|
|
626
|
+
) {
|
|
627
|
+
if (!ownerByPath?.size || !Array.isArray(components)) {
|
|
628
|
+
return 0;
|
|
629
|
+
}
|
|
630
|
+
const rootPrefix = rootDir
|
|
631
|
+
? rootDir.replaceAll("\\", "/").replace(/\/+$/, "")
|
|
632
|
+
: undefined;
|
|
633
|
+
let marked = 0;
|
|
634
|
+
for (const component of components) {
|
|
635
|
+
const purl = component?.purl;
|
|
636
|
+
if (
|
|
637
|
+
typeof purl !== "string" ||
|
|
638
|
+
!purl.startsWith("pkg:") ||
|
|
639
|
+
OS_PACKAGE_PURL_PREFIXES.some((prefix) => purl.startsWith(prefix)) ||
|
|
640
|
+
!Array.isArray(component.properties) ||
|
|
641
|
+
component.properties.some((prop) => prop.name === "cdx:os:installedBy")
|
|
642
|
+
) {
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
645
|
+
const owners = new Set();
|
|
646
|
+
let records = 0;
|
|
647
|
+
let unowned = 0;
|
|
648
|
+
for (const prop of component.properties) {
|
|
649
|
+
if (prop.name !== "internal:SrcFile" || typeof prop.value !== "string") {
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
let filePath = prop.value.replaceAll("\\", "/");
|
|
653
|
+
if (rootPrefix && filePath.startsWith(`${rootPrefix}/`)) {
|
|
654
|
+
filePath = filePath.slice(rootPrefix.length);
|
|
655
|
+
}
|
|
656
|
+
filePath = filePath.replace(/^\/+/, "");
|
|
657
|
+
if (!isInstallRecord(filePath)) {
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
records += 1;
|
|
661
|
+
const owner = ownerByPath.get(filePath);
|
|
662
|
+
if (owner) {
|
|
663
|
+
owners.add(owner);
|
|
664
|
+
} else {
|
|
665
|
+
unowned += 1;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (!records || unowned) {
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
for (const owner of Array.from(owners).sort()) {
|
|
672
|
+
component.properties.push({ name: "cdx:os:installedBy", value: owner });
|
|
673
|
+
}
|
|
674
|
+
marked += 1;
|
|
675
|
+
}
|
|
676
|
+
return marked;
|
|
677
|
+
}
|