@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
|
@@ -20,16 +20,10 @@
|
|
|
20
20
|
// The runtime component helpers at the end are the one place a PHP version
|
|
21
21
|
// becomes a component, for the container scan, the OS scan and formulation.
|
|
22
22
|
|
|
23
|
-
import {
|
|
24
|
-
closeSync,
|
|
25
|
-
fstatSync,
|
|
26
|
-
lstatSync,
|
|
27
|
-
openSync,
|
|
28
|
-
readSync,
|
|
29
|
-
realpathSync,
|
|
30
|
-
} from "node:fs";
|
|
23
|
+
import { closeSync, readSync } from "node:fs";
|
|
31
24
|
import { basename, join, resolve, sep } from "node:path";
|
|
32
25
|
|
|
26
|
+
import { openRegularFile } from "../core/boundedFile.js";
|
|
33
27
|
import { applyPurl, tryBuildPurl } from "./purl.js";
|
|
34
28
|
|
|
35
29
|
// The version grammar the contract accepts: M.m.p, optionally with -dev or an
|
|
@@ -187,53 +181,6 @@ export function classifyPhpSapi(fileName) {
|
|
|
187
181
|
return undefined;
|
|
188
182
|
}
|
|
189
183
|
|
|
190
|
-
/**
|
|
191
|
-
* Open a path only when it is a regular file that does not resolve outside
|
|
192
|
-
* rootDir. lstat runs first so a FIFO is rejected without opening it (an
|
|
193
|
-
* open on a FIFO blocks until a writer appears) and a symlink is never
|
|
194
|
-
* followed.
|
|
195
|
-
*
|
|
196
|
-
* @param {string} absPath absolute path
|
|
197
|
-
* @param {string|undefined} rootDir extracted root the path must stay under
|
|
198
|
-
* @returns {{fd: number, size: number}|undefined}
|
|
199
|
-
*/
|
|
200
|
-
function openRegularFile(absPath, rootDir) {
|
|
201
|
-
let fd;
|
|
202
|
-
try {
|
|
203
|
-
if (typeof absPath !== "string" || !absPath) {
|
|
204
|
-
return undefined;
|
|
205
|
-
}
|
|
206
|
-
const lst = lstatSync(absPath);
|
|
207
|
-
if (!lst.isFile()) {
|
|
208
|
-
return undefined;
|
|
209
|
-
}
|
|
210
|
-
if (rootDir) {
|
|
211
|
-
const root = realpathSync(resolve(rootDir));
|
|
212
|
-
const real = realpathSync(absPath);
|
|
213
|
-
const rootPrefix = root.endsWith(sep) ? root : root + sep;
|
|
214
|
-
if (real !== root && !real.startsWith(rootPrefix)) {
|
|
215
|
-
return undefined;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
fd = openSync(absPath, "r");
|
|
219
|
-
const stats = fstatSync(fd);
|
|
220
|
-
if (!stats.isFile()) {
|
|
221
|
-
closeSync(fd);
|
|
222
|
-
return undefined;
|
|
223
|
-
}
|
|
224
|
-
return { fd, size: stats.size };
|
|
225
|
-
} catch {
|
|
226
|
-
if (fd !== undefined) {
|
|
227
|
-
try {
|
|
228
|
-
closeSync(fd);
|
|
229
|
-
} catch {
|
|
230
|
-
// already closed
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return undefined;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
184
|
function matchVersionAt(buffer, start, readLength) {
|
|
238
185
|
if (start >= readLength) {
|
|
239
186
|
return undefined;
|
|
@@ -266,15 +213,19 @@ function scanBinaryVersion(fd, size) {
|
|
|
266
213
|
return undefined;
|
|
267
214
|
}
|
|
268
215
|
// Only matches starting inside this window are new; the overlap exists so
|
|
269
|
-
// a version split at the window edge is readable.
|
|
270
|
-
|
|
271
|
-
|
|
216
|
+
// a version split at the window edge is readable. The last window has no
|
|
217
|
+
// next one, so everything it read is searched.
|
|
218
|
+
const isLast = position + read >= size;
|
|
219
|
+
const searchLimit = isLast ? read : Math.min(READ_CHUNK_BYTES, read);
|
|
220
|
+
// Bytes a previous, longer read left past `read` are never searched.
|
|
221
|
+
const window = buffer.subarray(0, read);
|
|
222
|
+
let offset = window.indexOf(MARKER);
|
|
272
223
|
while (offset !== -1 && offset < searchLimit) {
|
|
273
224
|
const version = matchVersionAt(buffer, offset + MARKER.length, read);
|
|
274
225
|
if (version) {
|
|
275
226
|
return version;
|
|
276
227
|
}
|
|
277
|
-
offset =
|
|
228
|
+
offset = window.indexOf(MARKER, offset + 1);
|
|
278
229
|
}
|
|
279
230
|
if (read < bufferSize) {
|
|
280
231
|
return undefined;
|
|
@@ -14,19 +14,7 @@
|
|
|
14
14
|
// A package database that exists but cannot be read leaves ownership unknown.
|
|
15
15
|
// Unknown is not unpackaged: it emits nothing and records a degradation.
|
|
16
16
|
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
basename,
|
|
20
|
-
dirname,
|
|
21
|
-
isAbsolute,
|
|
22
|
-
join,
|
|
23
|
-
posix,
|
|
24
|
-
relative,
|
|
25
|
-
resolve,
|
|
26
|
-
sep,
|
|
27
|
-
win32,
|
|
28
|
-
} from "node:path";
|
|
29
|
-
import process from "node:process";
|
|
17
|
+
import { dirname, join } from "node:path";
|
|
30
18
|
|
|
31
19
|
import {
|
|
32
20
|
isDryRun,
|
|
@@ -34,28 +22,18 @@ import {
|
|
|
34
22
|
recordActivity,
|
|
35
23
|
} from "../core/activity.js";
|
|
36
24
|
import { recordDegradation } from "../core/buildLedger.js";
|
|
37
|
-
import { safeExistsSync, safeReadFileSync } from "../core/fs.js";
|
|
38
|
-
import { thoughtLog } from "../core/logger.js";
|
|
39
25
|
import {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
isDirectory,
|
|
27
|
+
listDirectory,
|
|
28
|
+
probeHostRuntime,
|
|
29
|
+
} from "./hostRuntimeProbe.js";
|
|
43
30
|
import {
|
|
44
31
|
attachPhpBuild,
|
|
45
32
|
classifyPhpSapi,
|
|
46
33
|
createPhpRuntimeInventory,
|
|
47
34
|
MAX_PHP_PROBES,
|
|
48
|
-
packageStoreOf,
|
|
49
35
|
readPhpBuildVersion,
|
|
50
36
|
} from "./phpBuildInfo.js";
|
|
51
|
-
import { tryBuildPurl } from "./purl.js";
|
|
52
|
-
|
|
53
|
-
// One dpkg list, and every dpkg list together. A database past these caps
|
|
54
|
-
// counts as unreadable instead of being read in part; the apk database has the
|
|
55
|
-
// same cap in its reader.
|
|
56
|
-
const MAX_DATABASE_FILE_BYTES = 64 * 1024 * 1024;
|
|
57
|
-
const MAX_DATABASE_TOTAL_BYTES = 256 * 1024 * 1024;
|
|
58
|
-
const MAX_DPKG_LISTS = 100000;
|
|
59
37
|
|
|
60
38
|
// Where the PHP of a source build is installed, relative to the root. `only`
|
|
61
39
|
// narrows a directory to one SAPI. `opt/*/bin` and `opt/*/sbin` read /opt one
|
|
@@ -98,193 +76,6 @@ function isWindowsCoreLibrary(name) {
|
|
|
98
76
|
return /^\d+$/.test(stem.endsWith("ts") ? stem.slice(0, -2) : stem);
|
|
99
77
|
}
|
|
100
78
|
|
|
101
|
-
function listDirectory(directory) {
|
|
102
|
-
try {
|
|
103
|
-
return readdirSync(directory).sort();
|
|
104
|
-
} catch {
|
|
105
|
-
return [];
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function isDirectory(path) {
|
|
110
|
-
try {
|
|
111
|
-
return statSync(path).isDirectory();
|
|
112
|
-
} catch {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function realPathOf(path) {
|
|
118
|
-
try {
|
|
119
|
-
return realpathSync(path);
|
|
120
|
-
} catch {
|
|
121
|
-
return undefined;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function quoteForOsquery(value) {
|
|
126
|
-
return `'${value.replaceAll("'", "''")}'`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function byBomRef(a, b) {
|
|
130
|
-
const left = a["bom-ref"];
|
|
131
|
-
const right = b["bom-ref"];
|
|
132
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function readBounded(file, maxBytes) {
|
|
136
|
-
try {
|
|
137
|
-
const stats = statSync(file);
|
|
138
|
-
if (!stats.isFile() || stats.size > maxBytes) {
|
|
139
|
-
return undefined;
|
|
140
|
-
}
|
|
141
|
-
} catch {
|
|
142
|
-
return undefined;
|
|
143
|
-
}
|
|
144
|
-
const text = safeReadFileSync(file, "utf-8");
|
|
145
|
-
return typeof text === "string" ? text : undefined;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// A package database: its name and path, `absent` when the host has none,
|
|
149
|
-
// `unreadable` when it has one that could not be read in full, and the paths of
|
|
150
|
-
// the candidates it lists.
|
|
151
|
-
function database(name, path, state = "ok") {
|
|
152
|
-
return { name, path, state, owned: new Set() };
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// dpkg keeps one <package>.list per package, naming each path as it is on the
|
|
156
|
-
// system.
|
|
157
|
-
function scanDpkg(infoDirectory, wanted) {
|
|
158
|
-
const result = database("dpkg", infoDirectory);
|
|
159
|
-
if (!safeExistsSync(infoDirectory)) {
|
|
160
|
-
result.state = "absent";
|
|
161
|
-
return result;
|
|
162
|
-
}
|
|
163
|
-
const lists = listDirectory(infoDirectory).filter((name) =>
|
|
164
|
-
name.endsWith(".list"),
|
|
165
|
-
);
|
|
166
|
-
if (!isDirectory(infoDirectory) || lists.length > MAX_DPKG_LISTS) {
|
|
167
|
-
result.state = "unreadable";
|
|
168
|
-
}
|
|
169
|
-
let total = 0;
|
|
170
|
-
for (const name of lists.slice(0, MAX_DPKG_LISTS)) {
|
|
171
|
-
const text = readBounded(
|
|
172
|
-
join(infoDirectory, name),
|
|
173
|
-
Math.min(MAX_DATABASE_FILE_BYTES, MAX_DATABASE_TOTAL_BYTES - total),
|
|
174
|
-
);
|
|
175
|
-
if (text === undefined) {
|
|
176
|
-
result.state = "unreadable";
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
total += text.length;
|
|
180
|
-
for (const line of text.split("\n")) {
|
|
181
|
-
if (wanted.has(line)) {
|
|
182
|
-
result.owned.add(line);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
return result;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// apk's installed database is read by the same reader the OS inventory uses, so
|
|
190
|
-
// the packages an OBOM lists and the files this probe treats as owned follow one
|
|
191
|
-
// parser. A dry run never gets here: probeHostPhp returns before it.
|
|
192
|
-
function scanApk(context, wanted) {
|
|
193
|
-
const { apkInstalledFile } = context.databases;
|
|
194
|
-
const apk = readApkInstalledDb({
|
|
195
|
-
rootPath: context.rootPath,
|
|
196
|
-
databaseFile: apkInstalledFile,
|
|
197
|
-
wantedFiles: wanted,
|
|
198
|
-
platform: context.platform,
|
|
199
|
-
});
|
|
200
|
-
const result = database(
|
|
201
|
-
"apk",
|
|
202
|
-
apk.path ||
|
|
203
|
-
apkInstalledFile ||
|
|
204
|
-
join(context.rootPath, APK_INSTALLED_DB_PATHS[0]),
|
|
205
|
-
);
|
|
206
|
-
result.state = { ok: "ok", unreadable: "unreadable" }[apk.state] || "absent";
|
|
207
|
-
for (const pkg of apk.packages) {
|
|
208
|
-
for (const file of pkg.files) {
|
|
209
|
-
result.owned.add(file);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
return result;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// osquery's rpm_package_files answers for a path without being told the
|
|
216
|
-
// package.
|
|
217
|
-
function queryRpm(databaseDirectories, wanted, executeOsQuery) {
|
|
218
|
-
const result = database("rpm", databaseDirectories[0]);
|
|
219
|
-
if (!databaseDirectories.some((directory) => safeExistsSync(directory))) {
|
|
220
|
-
result.state = "absent";
|
|
221
|
-
return result;
|
|
222
|
-
}
|
|
223
|
-
if (!wanted.size) {
|
|
224
|
-
return result;
|
|
225
|
-
}
|
|
226
|
-
const rows =
|
|
227
|
-
typeof executeOsQuery === "function"
|
|
228
|
-
? executeOsQuery(
|
|
229
|
-
`SELECT package, path FROM rpm_package_files WHERE path IN (${[
|
|
230
|
-
...wanted,
|
|
231
|
-
]
|
|
232
|
-
.map(quoteForOsquery)
|
|
233
|
-
.join(", ")})`,
|
|
234
|
-
)
|
|
235
|
-
: undefined;
|
|
236
|
-
if (!Array.isArray(rows)) {
|
|
237
|
-
result.state = "unreadable";
|
|
238
|
-
return result;
|
|
239
|
-
}
|
|
240
|
-
for (const row of rows) {
|
|
241
|
-
if (typeof row?.path === "string") {
|
|
242
|
-
result.owned.add(row.path);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
return result;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Chocolatey's database is the list of packages the OS scan has already made.
|
|
249
|
-
// The client is itself a package, so a Chocolatey with none listed was not
|
|
250
|
-
// listed: the query failed.
|
|
251
|
-
function readChocolatey(context) {
|
|
252
|
-
const configured =
|
|
253
|
-
context.readEnv("ChocolateyInstall") ||
|
|
254
|
-
join(context.rootPath, "ProgramData", "chocolatey");
|
|
255
|
-
const result = database("chocolatey", configured);
|
|
256
|
-
if (!safeExistsSync(configured)) {
|
|
257
|
-
result.state = "absent";
|
|
258
|
-
return result;
|
|
259
|
-
}
|
|
260
|
-
const packages = (context.packageComponents || []).filter((component) =>
|
|
261
|
-
component?.purl?.startsWith("pkg:chocolatey/"),
|
|
262
|
-
);
|
|
263
|
-
if (!packages.length) {
|
|
264
|
-
result.state = "unreadable";
|
|
265
|
-
return result;
|
|
266
|
-
}
|
|
267
|
-
result.directory = realPathOf(configured) || resolve(configured);
|
|
268
|
-
result.hasPhp = packages.some(
|
|
269
|
-
(component) => `${component.name}`.toLowerCase() === "php",
|
|
270
|
-
);
|
|
271
|
-
return result;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Chocolatey's php package unpacks under C:\tools by default, outside the
|
|
275
|
-
// package's own folder, so what makes a file Chocolatey's is the package being
|
|
276
|
-
// installed and the file being where the package puts it.
|
|
277
|
-
function chocolateyOwns(chocolatey, context, candidate) {
|
|
278
|
-
if (!chocolatey.hasPhp) {
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
const first = relative(context.realRoot, candidate.real).split(sep)[0];
|
|
282
|
-
return (
|
|
283
|
-
first.toLowerCase() === "tools" ||
|
|
284
|
-
candidate.real.startsWith(`${chocolatey.directory}${sep}`)
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
79
|
// The directories to look in, as absolute paths.
|
|
289
80
|
function candidateDirectories(context) {
|
|
290
81
|
const { rootPath, platform } = context;
|
|
@@ -318,197 +109,6 @@ function candidateDirectories(context) {
|
|
|
318
109
|
return directories;
|
|
319
110
|
}
|
|
320
111
|
|
|
321
|
-
// A path as the system being described names it, and as a purl subpath. `base`
|
|
322
|
-
// is the directory the path hangs off, so that a symlinked root, as a temporary
|
|
323
|
-
// directory often is, does not matter.
|
|
324
|
-
function locate(context, base, absolutePath) {
|
|
325
|
-
const parts = relative(base, absolutePath).split(sep);
|
|
326
|
-
return {
|
|
327
|
-
logical: context.pathApi.join(context.logicalRoot, ...parts),
|
|
328
|
-
subpath: parts.join("/"),
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* The distinct PHP files of the fixed directories, at most `maxProbes`. A
|
|
334
|
-
* symlink is read through to the file it names, which must itself be a PHP
|
|
335
|
-
* file under the root, and two names for one file are one candidate.
|
|
336
|
-
*
|
|
337
|
-
* @param {Object} context probe context
|
|
338
|
-
* @returns {Object[]} candidates with their real path, SAPI and locations
|
|
339
|
-
*/
|
|
340
|
-
function collectCandidates(context) {
|
|
341
|
-
const { realRoot, platform, maxProbes } = context;
|
|
342
|
-
const classify =
|
|
343
|
-
platform === "win32"
|
|
344
|
-
? (name) => WINDOWS_SAPIS[name.toLowerCase()]
|
|
345
|
-
: classifyPhpSapi;
|
|
346
|
-
const candidates = [];
|
|
347
|
-
const seen = new Set();
|
|
348
|
-
for (const { directory, only } of candidateDirectories(context)) {
|
|
349
|
-
for (const name of listDirectory(directory)) {
|
|
350
|
-
if (!classify(name)) {
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
const listed = join(directory, name);
|
|
354
|
-
const real = realPathOf(listed);
|
|
355
|
-
if (!real || seen.has(real)) {
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
const sapi = classify(basename(real));
|
|
359
|
-
const inside = relative(realRoot, real);
|
|
360
|
-
if (
|
|
361
|
-
!sapi ||
|
|
362
|
-
(only && sapi !== only) ||
|
|
363
|
-
!inside ||
|
|
364
|
-
inside.startsWith("..") ||
|
|
365
|
-
isAbsolute(inside)
|
|
366
|
-
) {
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
try {
|
|
370
|
-
if (!statSync(real).isFile()) {
|
|
371
|
-
continue;
|
|
372
|
-
}
|
|
373
|
-
} catch {
|
|
374
|
-
continue;
|
|
375
|
-
}
|
|
376
|
-
if (candidates.length >= maxProbes) {
|
|
377
|
-
thoughtLog(
|
|
378
|
-
`The PHP host probe looked at ${maxProbes} files and left any others unread.`,
|
|
379
|
-
);
|
|
380
|
-
return candidates;
|
|
381
|
-
}
|
|
382
|
-
seen.add(real);
|
|
383
|
-
candidates.push({
|
|
384
|
-
real,
|
|
385
|
-
sapi,
|
|
386
|
-
name: basename(real),
|
|
387
|
-
...locate(context, realRoot, real),
|
|
388
|
-
listedLogical: locate(context, context.rootPath, listed).logical,
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
return candidates;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
function recordUnreadable(unreadable, recorded) {
|
|
396
|
-
if (recorded.has(unreadable.name)) {
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
recorded.add(unreadable.name);
|
|
400
|
-
recordDegradation("php.host-probe.package-db-unreadable", {
|
|
401
|
-
ecosystem: "php",
|
|
402
|
-
tool: unreadable.name,
|
|
403
|
-
impact: "components",
|
|
404
|
-
path: unreadable.path,
|
|
405
|
-
detail: `The ${unreadable.name} package database could not be read in full, so PHP files it may own were not identified as unpackaged PHP.`,
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Sort the candidates into those a package owns, those whose ownership could
|
|
411
|
-
* not be settled, and the unpackaged rest.
|
|
412
|
-
*
|
|
413
|
-
* @param {Object[]} candidates candidates from collectCandidates
|
|
414
|
-
* @param {Object} context probe context
|
|
415
|
-
* @returns {{unpackaged: Object[], owned: number, unknown: number}}
|
|
416
|
-
*/
|
|
417
|
-
function classifyOwnership(candidates, context) {
|
|
418
|
-
const unpackaged = [];
|
|
419
|
-
const recorded = new Set();
|
|
420
|
-
let owned = 0;
|
|
421
|
-
let unknown = 0;
|
|
422
|
-
const pending = candidates.filter((candidate) => {
|
|
423
|
-
if (packageStoreOf(candidate.logical)) {
|
|
424
|
-
owned++;
|
|
425
|
-
return false;
|
|
426
|
-
}
|
|
427
|
-
return true;
|
|
428
|
-
});
|
|
429
|
-
if (!pending.length) {
|
|
430
|
-
return { unpackaged, owned, unknown };
|
|
431
|
-
}
|
|
432
|
-
const wanted = new Set(
|
|
433
|
-
pending.flatMap((candidate) => [
|
|
434
|
-
candidate.logical,
|
|
435
|
-
candidate.listedLogical,
|
|
436
|
-
]),
|
|
437
|
-
);
|
|
438
|
-
const databases = [];
|
|
439
|
-
if (context.platform === "win32") {
|
|
440
|
-
databases.push(readChocolatey(context));
|
|
441
|
-
} else {
|
|
442
|
-
const { dpkgInfoDirectory, rpmDatabaseDirectories } = context.databases;
|
|
443
|
-
databases.push(
|
|
444
|
-
scanDpkg(dpkgInfoDirectory, wanted),
|
|
445
|
-
scanApk(context, wanted),
|
|
446
|
-
);
|
|
447
|
-
// Only what dpkg and apk did not claim is asked of osquery.
|
|
448
|
-
const claimed = new Set(databases.flatMap((db) => [...db.owned]));
|
|
449
|
-
databases.push(
|
|
450
|
-
queryRpm(
|
|
451
|
-
rpmDatabaseDirectories,
|
|
452
|
-
new Set([...wanted].filter((path) => !claimed.has(path))),
|
|
453
|
-
context.executeOsQuery,
|
|
454
|
-
),
|
|
455
|
-
);
|
|
456
|
-
}
|
|
457
|
-
for (const candidate of pending) {
|
|
458
|
-
const paths = [candidate.logical, candidate.listedLogical];
|
|
459
|
-
const isOwned = databases.some(
|
|
460
|
-
(db) =>
|
|
461
|
-
db.state === "ok" &&
|
|
462
|
-
(db.name === "chocolatey"
|
|
463
|
-
? chocolateyOwns(db, context, candidate)
|
|
464
|
-
: paths.some((path) => db.owned.has(path))),
|
|
465
|
-
);
|
|
466
|
-
if (isOwned) {
|
|
467
|
-
owned++;
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
const unreadable = databases.filter((db) => db.state === "unreadable");
|
|
471
|
-
if (!unreadable.length) {
|
|
472
|
-
unpackaged.push(candidate);
|
|
473
|
-
continue;
|
|
474
|
-
}
|
|
475
|
-
unknown++;
|
|
476
|
-
for (const db of unreadable) {
|
|
477
|
-
recordUnreadable(db, recorded);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
return { unpackaged, owned, unknown };
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
// Like a container's unpackaged files, but named by where they are: a host can
|
|
484
|
-
// hold several binaries of one name.
|
|
485
|
-
function fileComponent(candidate) {
|
|
486
|
-
const purl = tryBuildPurl({
|
|
487
|
-
type: "generic",
|
|
488
|
-
name: candidate.name,
|
|
489
|
-
subpath: candidate.subpath,
|
|
490
|
-
});
|
|
491
|
-
return {
|
|
492
|
-
name: candidate.name,
|
|
493
|
-
type: "file",
|
|
494
|
-
...(purl ? { purl } : {}),
|
|
495
|
-
"bom-ref": purl ? decodeURIComponent(purl) : `file:${candidate.logical}`,
|
|
496
|
-
properties: [{ name: "internal:SrcFile", value: candidate.logical }],
|
|
497
|
-
evidence: {
|
|
498
|
-
identity: [
|
|
499
|
-
{
|
|
500
|
-
field: "purl",
|
|
501
|
-
confidence: 0,
|
|
502
|
-
methods: [
|
|
503
|
-
{ technique: "filename", confidence: 0, value: candidate.logical },
|
|
504
|
-
],
|
|
505
|
-
concludedValue: candidate.logical,
|
|
506
|
-
},
|
|
507
|
-
],
|
|
508
|
-
},
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
|
|
512
112
|
// On Windows the CGI and debugger executables hold no version; the core DLL in
|
|
513
113
|
// the same directory does.
|
|
514
114
|
function readBuild(context, candidate) {
|
|
@@ -531,36 +131,6 @@ function readBuild(context, candidate) {
|
|
|
531
131
|
return undefined;
|
|
532
132
|
}
|
|
533
133
|
|
|
534
|
-
function createContext(options, platform, readEnv, logicalRoot) {
|
|
535
|
-
const rootPath = options.rootPath || logicalRoot;
|
|
536
|
-
const realRoot = realPathOf(rootPath);
|
|
537
|
-
if (!realRoot) {
|
|
538
|
-
return undefined;
|
|
539
|
-
}
|
|
540
|
-
const databases = options.packageDatabases || {};
|
|
541
|
-
return {
|
|
542
|
-
platform,
|
|
543
|
-
readEnv,
|
|
544
|
-
rootPath,
|
|
545
|
-
realRoot,
|
|
546
|
-
logicalRoot,
|
|
547
|
-
pathApi: platform === "win32" ? win32 : posix,
|
|
548
|
-
maxProbes: options.maxProbes || MAX_PHP_PROBES,
|
|
549
|
-
executeOsQuery: options.executeOsQuery,
|
|
550
|
-
packageComponents: options.packageComponents,
|
|
551
|
-
databases: {
|
|
552
|
-
dpkgInfoDirectory:
|
|
553
|
-
databases.dpkgInfoDirectory || join(rootPath, "var/lib/dpkg/info"),
|
|
554
|
-
// Unset, the reader looks where apk keeps the database under the root.
|
|
555
|
-
apkInstalledFile: databases.apkInstalledFile,
|
|
556
|
-
rpmDatabaseDirectories: databases.rpmDatabaseDirectories || [
|
|
557
|
-
join(rootPath, "var/lib/rpm"),
|
|
558
|
-
join(rootPath, "usr/lib/sysimage/rpm"),
|
|
559
|
-
],
|
|
560
|
-
},
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
|
|
564
134
|
/**
|
|
565
135
|
* Look for PHP no package manager owns, in the fixed directories of the host.
|
|
566
136
|
* Components come back only for the files nothing owns: a `file` component for
|
|
@@ -583,59 +153,33 @@ function createContext(options, platform, readEnv, logicalRoot) {
|
|
|
583
153
|
* @returns {{components: Object[], dependencies: Object[]}}
|
|
584
154
|
*/
|
|
585
155
|
export function probeHostPhp(options = {}) {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
options.env ? options.env[name] : readEnvironmentVariable(name);
|
|
590
|
-
const logicalRoot =
|
|
591
|
-
platform === "win32" ? `${readEnv("SystemDrive") || "C:"}\\` : "/";
|
|
592
|
-
if (isDryRun) {
|
|
593
|
-
recordActivity({
|
|
594
|
-
capability: "php-host-probe",
|
|
595
|
-
kind: "read",
|
|
596
|
-
reason:
|
|
597
|
-
"Dry run mode blocks the PHP host probe, which opens executables and package databases outside the project.",
|
|
598
|
-
status: "blocked",
|
|
599
|
-
target: options.rootPath || logicalRoot,
|
|
600
|
-
});
|
|
601
|
-
return empty;
|
|
602
|
-
}
|
|
603
|
-
const context = createContext(options, platform, readEnv, logicalRoot);
|
|
604
|
-
if (!context) {
|
|
605
|
-
return empty;
|
|
606
|
-
}
|
|
607
|
-
const candidates = collectCandidates(context);
|
|
608
|
-
if (!candidates.length) {
|
|
609
|
-
return empty;
|
|
610
|
-
}
|
|
611
|
-
const { unpackaged, owned, unknown } = classifyOwnership(candidates, context);
|
|
612
|
-
const inventory = createPhpRuntimeInventory();
|
|
613
|
-
const files = [];
|
|
614
|
-
for (const candidate of unpackaged) {
|
|
615
|
-
const build = readBuild(context, candidate);
|
|
616
|
-
if (build) {
|
|
617
|
-
const component = fileComponent(candidate);
|
|
618
|
-
attachPhpBuild(inventory, component, build, candidate.sapi);
|
|
619
|
-
files.push(component);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
recordActivity({
|
|
156
|
+
return probeHostRuntime(options, {
|
|
157
|
+
label: "PHP",
|
|
158
|
+
ecosystem: "php",
|
|
623
159
|
capability: "php-host-probe",
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
160
|
+
remediationId: "php.host-probe.package-db-unreadable",
|
|
161
|
+
maxProbes: MAX_PHP_PROBES,
|
|
162
|
+
chocolateyPackages: ["php"],
|
|
163
|
+
// Chocolatey's php package unpacks under C:\tools by default.
|
|
164
|
+
chocolateyDirectories: (context) => [join(context.rootPath, "tools")],
|
|
165
|
+
directories: candidateDirectories,
|
|
166
|
+
classify: (name, platform) =>
|
|
167
|
+
platform === "win32"
|
|
168
|
+
? WINDOWS_SAPIS[name.toLowerCase()]
|
|
169
|
+
: classifyPhpSapi(name),
|
|
170
|
+
readBuild,
|
|
171
|
+
createInventory: createPhpRuntimeInventory,
|
|
172
|
+
attach: (inventory, component, build, candidate) =>
|
|
173
|
+
attachPhpBuild(inventory, component, build, candidate.kind),
|
|
174
|
+
finish: (inventory) => ({
|
|
175
|
+
components: inventory.runtimeComponents,
|
|
176
|
+
dependencies: inventory.dependencies,
|
|
177
|
+
}),
|
|
178
|
+
hooks: {
|
|
179
|
+
isDryRun,
|
|
180
|
+
readEnvironmentVariable,
|
|
181
|
+
recordActivity,
|
|
182
|
+
recordDegradation,
|
|
183
|
+
},
|
|
628
184
|
});
|
|
629
|
-
if (files.length) {
|
|
630
|
-
thoughtLog(
|
|
631
|
-
`I found ${files.length} unpackaged PHP file(s) on this host, from ${inventory.runtimeComponents.length} version(s).`,
|
|
632
|
-
);
|
|
633
|
-
}
|
|
634
|
-
return {
|
|
635
|
-
components: [
|
|
636
|
-
...files.sort(byBomRef),
|
|
637
|
-
...inventory.runtimeComponents.sort(byBomRef),
|
|
638
|
-
],
|
|
639
|
-
dependencies: inventory.dependencies,
|
|
640
|
-
};
|
|
641
185
|
}
|