@cdxgen/cdxgen 13.3.0 → 13.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -9
- package/bin/cdxgen-secure.js +15 -0
- package/bin/cdxgen.js +115 -31
- package/bin/evinse.js +23 -1
- package/bin/hbom.js +15 -7
- package/bin/repl.js +115 -0
- package/bin/sign.js +45 -15
- package/bin/tracebom.js +5 -1
- package/bin/validate.js +84 -18
- package/bin/verify.js +155 -86
- package/data/cbomosdb-queries.json +13 -1
- package/data/component-tags.json +8 -0
- package/data/helpers/init.gradle +46 -21
- package/data/queries-darwin.json +25 -1
- package/data/queries-win.json +19 -1
- package/data/queries.json +41 -0
- package/data/remediations.json +344 -1
- package/data/rules/cbom-security.yaml +235 -4
- package/data/rules/dependency-sources.yaml +67 -0
- package/data/rules/go-binaries.yaml +46 -0
- package/data/rules/golem-go.yaml +80 -0
- package/data/rules/hbom-compliance.yaml +40 -22
- package/data/rules/hbom-performance.yaml +7 -1
- package/data/rules/host-topology.yaml +1 -1
- package/data/rules/obom-runtime.yaml +31 -2
- package/data/rules/php-runtime.yaml +143 -0
- package/data/rules/scala-evidence.yaml +115 -0
- package/lib/audit/index.js +52 -6
- package/lib/cli/bomAssembly.js +28 -3
- package/lib/cli/cliOptions.js +110 -3
- package/lib/cli/index.js +186 -58
- package/lib/cli/jsBom.js +50 -29
- package/lib/cli/jvmBom.js +779 -146
- package/lib/cli/managedBom.js +1021 -261
- package/lib/cli/nativeBom.js +364 -58
- package/lib/core/activity.js +12 -0
- package/lib/core/env.js +47 -17
- package/lib/core/fs.js +31 -21
- package/lib/core/httpClient.js +233 -69
- package/lib/core/pluginRun.js +184 -0
- package/lib/core/processTree.js +100 -0
- package/lib/core/projectConfig.js +1 -0
- package/lib/core/projectTooling.js +97 -0
- package/lib/core/propertySanitizer.js +72 -0
- package/lib/core/runState.js +39 -0
- package/lib/core/toml.js +72 -0
- package/lib/ecosystems/asarutils.js +4 -2
- package/lib/ecosystems/bunutils.js +5 -7
- package/lib/ecosystems/cargoCache.js +231 -8
- package/lib/ecosystems/cmakeResolver.js +10 -21
- package/lib/ecosystems/cppBuildContext.js +631 -0
- package/lib/ecosystems/cppEvidence.js +337 -22
- package/lib/ecosystems/cppIncludeResolver.js +294 -0
- package/lib/ecosystems/denoutils.js +93 -66
- package/lib/ecosystems/ecosystems.js +1967 -788
- package/lib/ecosystems/golem.js +578 -18
- package/lib/ecosystems/gradleutils.js +340 -46
- package/lib/ecosystems/jsEvidence.js +85 -24
- package/lib/ecosystems/kosi.js +21 -4
- package/lib/ecosystems/npmutils.js +64 -0
- package/lib/ecosystems/parsers-dotnet.js +668 -153
- package/lib/ecosystems/parsers-elm.js +46 -28
- package/lib/ecosystems/parsers-gleam.js +3 -4
- package/lib/ecosystems/parsers-go.js +1283 -297
- package/lib/ecosystems/parsers-js.js +92 -26
- package/lib/ecosystems/parsers-julia.js +2 -3
- package/lib/ecosystems/parsers-jvm.js +463 -29
- package/lib/ecosystems/parsers-misc.js +405 -93
- package/lib/ecosystems/parsers-python.js +152 -20
- package/lib/ecosystems/parsers-rust.js +4 -4
- package/lib/ecosystems/parsers-terraform.js +1573 -19
- package/lib/ecosystems/pythonutils.js +102 -6
- package/lib/ecosystems/remote/huggingface.js +3 -0
- package/lib/ecosystems/rubyutils.js +73 -20
- package/lib/ecosystems/rusi.js +32 -9
- package/lib/ecosystems/sbtutils.js +243 -187
- package/lib/ecosystems/scalacliutils.js +343 -0
- package/lib/ecosystems/scalasem.js +2620 -0
- package/lib/ecosystems/terraformRegistry.js +288 -0
- package/lib/ecosystems/utils.js +2 -0
- package/lib/ecosystems/vendoredCode.js +156 -0
- package/lib/evinser/evinser.js +695 -78
- package/lib/evinser/swiftsem.js +68 -5
- package/lib/helpers/agenticToolutils.js +2 -2
- package/lib/helpers/bomSigner.js +576 -128
- package/lib/inventory/agentSkillSpec.js +17 -0
- package/lib/inventory/aiCollector.js +4 -1
- package/lib/inventory/analyzer.js +110 -127
- package/lib/inventory/apkInstalledDb.js +243 -0
- package/lib/inventory/atomUtils.js +204 -48
- package/lib/inventory/auditCategories.js +10 -3
- package/lib/inventory/buildToolRateLimit.js +144 -0
- package/lib/inventory/cacheCommands.js +2 -1
- package/lib/inventory/cacheDir.js +52 -9
- package/lib/inventory/certificates.js +2371 -0
- package/lib/inventory/cmakeBuildDirs.js +254 -0
- package/lib/inventory/communityAiConfigParser.js +4 -9
- package/lib/inventory/deps.js +507 -128
- package/lib/inventory/display.js +200 -3
- package/lib/inventory/dosai.js +747 -101
- package/lib/inventory/dosaiParsers.js +310 -15
- package/lib/inventory/dynamic.js +96 -8
- package/lib/inventory/envcontext.js +168 -5
- package/lib/inventory/evidenceUtils.js +590 -132
- package/lib/inventory/fetchBatch.js +574 -38
- package/lib/inventory/fetchDiskCache.js +597 -0
- package/lib/inventory/forgeEnricher.js +14 -5
- package/lib/inventory/formulationParsers.js +3 -2
- package/lib/inventory/goBuildInfo.js +140 -0
- package/lib/inventory/hbom.js +67 -7
- package/lib/inventory/hbomAnalysis.js +16 -0
- package/lib/inventory/hostTopology.js +21 -0
- package/lib/inventory/jvmLocalRepos.js +917 -0
- package/lib/inventory/mcpConfigParser.js +2 -3
- package/lib/inventory/osPackagePurl.js +244 -0
- package/lib/inventory/osPackageResolver.js +89 -87
- package/lib/inventory/osinfo.js +79 -31
- package/lib/inventory/osqueryTransform.js +114 -5
- package/lib/inventory/parentSelection.js +146 -0
- package/lib/inventory/phpBuildInfo.js +487 -0
- package/lib/inventory/phpHostProbe.js +641 -0
- package/lib/inventory/rootfsCerts.js +426 -0
- package/lib/inventory/rustFormulationParser.js +3 -4
- package/lib/inventory/scalaCoords.js +153 -0
- package/lib/inventory/source.js +215 -11
- package/lib/inventory/spdx.js +245 -0
- package/lib/inventory/traceRunner.js +93 -8
- package/lib/inventory/tracedCrypto.js +423 -0
- package/lib/managers/binary.js +529 -183
- package/lib/managers/docker.js +199 -44
- package/lib/managers/oci.js +24 -2
- package/lib/parsers/cmakeCache.js +69 -0
- package/lib/parsers/cmakeLists.js +16 -2
- package/lib/parsers/cmakePresets.js +400 -0
- package/lib/parsers/compileCommands.js +557 -0
- package/lib/parsers/email.js +277 -0
- package/lib/parsers/largeJson.js +34 -2
- package/lib/parsers/strictJson.js +322 -0
- package/lib/parsers/terraformConfig.js +1073 -0
- package/lib/parsers/terraformSource.js +652 -0
- package/lib/server/server.js +209 -1
- package/lib/stages/postgen/annotator.js +17 -1
- package/lib/stages/postgen/introspection/markers.js +1 -1
- package/lib/stages/postgen/introspection/reflect.js +4 -1
- package/lib/stages/postgen/postgen.js +20 -6
- package/lib/stages/postgen/ruleEngine.js +58 -1
- package/lib/stages/postgen/specVersionCompat.js +62 -0
- package/lib/stages/pregen/pregen.js +117 -5
- package/lib/validator/bomValidator.js +26 -5
- package/lib/validator/generated/runtime.mjs +13 -0
- package/lib/validator/generated/validate-1.6.mjs +26 -7
- package/lib/validator/generated/validate-1.7.mjs +31 -12
- package/lib/validator/generated/validate-2.0.mjs +30 -11
- package/lib/validator/index.js +25 -10
- package/lib/validator/reporters/json.js +1 -0
- package/package.json +23 -23
- package/types/bin/cdxgen-secure.d.ts +3 -0
- package/types/bin/cdxgen-secure.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +9 -2
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +43 -0
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +44 -1
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts +7 -4
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts +3 -1
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/activity.d.ts.map +1 -1
- package/types/lib/core/env.d.ts +27 -2
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/httpClient.d.ts +13 -8
- package/types/lib/core/httpClient.d.ts.map +1 -1
- package/types/lib/core/pluginRun.d.ts +97 -0
- package/types/lib/core/pluginRun.d.ts.map +1 -0
- package/types/lib/core/processTree.d.ts +36 -0
- package/types/lib/core/processTree.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/projectTooling.d.ts +41 -0
- package/types/lib/core/projectTooling.d.ts.map +1 -0
- package/types/lib/core/propertySanitizer.d.ts +26 -0
- package/types/lib/core/propertySanitizer.d.ts.map +1 -1
- package/types/lib/core/runState.d.ts +29 -0
- package/types/lib/core/runState.d.ts.map +1 -0
- package/types/lib/core/toml.d.ts +20 -0
- package/types/lib/core/toml.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
- package/types/lib/ecosystems/cargoCache.d.ts +12 -0
- package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
- package/types/lib/ecosystems/cmakeResolver.d.ts +5 -3
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
- package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +19 -3
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
- package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +9 -3
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts +62 -13
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/golem.d.ts +81 -1
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +59 -7
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts.map +1 -1
- package/types/lib/ecosystems/npmutils.d.ts +15 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-dotnet.d.ts +155 -5
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-go.d.ts +119 -5
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +6 -1
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts +74 -3
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +21 -59
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +57 -6
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
- package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +26 -1
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +21 -1
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/ecosystems/sbtutils.d.ts +88 -2
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
- package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
- package/types/lib/ecosystems/scalasem.d.ts +311 -0
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +2 -2
- package/types/lib/ecosystems/utils.d.ts.map +1 -1
- package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
- package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +100 -8
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/swiftsem.d.ts +10 -0
- package/types/lib/evinser/swiftsem.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +80 -4
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/inventory/agentSkillSpec.d.ts +13 -0
- package/types/lib/inventory/agentSkillSpec.d.ts.map +1 -0
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/analyzer.d.ts.map +1 -1
- package/types/lib/inventory/apkInstalledDb.d.ts +42 -0
- package/types/lib/inventory/apkInstalledDb.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +96 -10
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +3 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
- package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +2 -1
- package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
- package/types/lib/inventory/cacheDir.d.ts +12 -4
- package/types/lib/inventory/cacheDir.d.ts.map +1 -1
- package/types/lib/inventory/certificates.d.ts +205 -0
- package/types/lib/inventory/certificates.d.ts.map +1 -0
- package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
- package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/deps.d.ts +61 -2
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/display.d.ts +18 -0
- package/types/lib/inventory/display.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +202 -14
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dosaiParsers.d.ts +53 -7
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts +16 -1
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/envcontext.d.ts +40 -2
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts +48 -14
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/fetchBatch.d.ts +83 -14
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
- package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
- package/types/lib/inventory/goBuildInfo.d.ts +10 -0
- package/types/lib/inventory/goBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -1
- package/types/lib/inventory/hbomAnalysis.d.ts +10 -0
- package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -1
- package/types/lib/inventory/hostTopology.d.ts.map +1 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/osPackagePurl.d.ts +99 -0
- package/types/lib/inventory/osPackagePurl.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +6 -2
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
- package/types/lib/inventory/osinfo.d.ts +31 -6
- package/types/lib/inventory/osinfo.d.ts.map +1 -1
- package/types/lib/inventory/osqueryTransform.d.ts +51 -0
- package/types/lib/inventory/osqueryTransform.d.ts.map +1 -1
- package/types/lib/inventory/parentSelection.d.ts +34 -0
- package/types/lib/inventory/parentSelection.d.ts.map +1 -0
- package/types/lib/inventory/phpBuildInfo.d.ts +142 -0
- package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/phpHostProbe.d.ts +35 -0
- package/types/lib/inventory/phpHostProbe.d.ts.map +1 -0
- package/types/lib/inventory/rootfsCerts.d.ts +27 -0
- package/types/lib/inventory/rootfsCerts.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/scalaCoords.d.ts +80 -0
- package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +28 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/spdx.d.ts +24 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -1
- package/types/lib/inventory/traceRunner.d.ts +16 -1
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/inventory/tracedCrypto.d.ts +64 -0
- package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
- package/types/lib/managers/binary.d.ts +10 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +12 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +3 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/parsers/cmakeCache.d.ts +16 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
- package/types/lib/parsers/cmakeLists.d.ts +2 -1
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -1
- package/types/lib/parsers/cmakePresets.d.ts +78 -0
- package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
- package/types/lib/parsers/compileCommands.d.ts +115 -0
- package/types/lib/parsers/compileCommands.d.ts.map +1 -0
- package/types/lib/parsers/email.d.ts +19 -0
- package/types/lib/parsers/email.d.ts.map +1 -0
- package/types/lib/parsers/largeJson.d.ts +13 -0
- package/types/lib/parsers/largeJson.d.ts.map +1 -1
- package/types/lib/parsers/strictJson.d.ts +46 -0
- package/types/lib/parsers/strictJson.d.ts.map +1 -0
- package/types/lib/parsers/terraformConfig.d.ts +70 -0
- package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
- package/types/lib/parsers/terraformSource.d.ts +66 -0
- package/types/lib/parsers/terraformSource.d.ts.map +1 -0
- package/types/lib/server/server.d.ts +8 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts +7 -4
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/stages/pregen/pregen.d.ts +14 -1
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +8 -0
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
|
@@ -6,7 +6,13 @@ import {
|
|
|
6
6
|
statSync,
|
|
7
7
|
} from "node:fs";
|
|
8
8
|
import { tmpdir, totalmem } from "node:os";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
delimiter as _delimiter,
|
|
11
|
+
basename,
|
|
12
|
+
dirname,
|
|
13
|
+
join,
|
|
14
|
+
resolve,
|
|
15
|
+
} from "node:path";
|
|
10
16
|
import process from "node:process";
|
|
11
17
|
|
|
12
18
|
import {
|
|
@@ -23,7 +29,10 @@ import {
|
|
|
23
29
|
} from "../core/fs.js";
|
|
24
30
|
import { TRACE_MODE } from "../core/logger.js";
|
|
25
31
|
import { dirNameStr, isWin } from "../core/paths.js";
|
|
32
|
+
import { formatDuration, reapProcessTree } from "../core/processTree.js";
|
|
33
|
+
import { isProjectToolingAllowed } from "../core/projectTooling.js";
|
|
26
34
|
import { readJsonFile } from "../parsers/largeJson.js";
|
|
35
|
+
import { cmakeBuildDirCandidates } from "./cmakeBuildDirs.js";
|
|
27
36
|
|
|
28
37
|
const ASTGEN_DEFAULT_IGNORE_DIRS = [
|
|
29
38
|
"venv",
|
|
@@ -83,9 +92,6 @@ const ATOM_C_LANGUAGES = new Set([
|
|
|
83
92
|
|
|
84
93
|
const COMPILE_COMMANDS_FILE = "compile_commands.json";
|
|
85
94
|
|
|
86
|
-
/** Build directories, under the scan root, searched for a compilation database. */
|
|
87
|
-
const COMPILE_COMMANDS_BUILD_DIRS = ["build", "out", "builddir"];
|
|
88
|
-
|
|
89
95
|
/**
|
|
90
96
|
* Characters a Windows shell command line would interpret: `&`, `|`, `<` and
|
|
91
97
|
* `>` chain or redirect commands, `%` expands variables even inside quotes,
|
|
@@ -117,9 +123,12 @@ function compileCommandsIn(dir) {
|
|
|
117
123
|
* language its build uses.
|
|
118
124
|
*
|
|
119
125
|
* An explicit `options.compileCommands` (a file, or a directory holding one
|
|
120
|
-
* directly or under `build/`) wins. Otherwise the scan root
|
|
121
|
-
*
|
|
122
|
-
*
|
|
126
|
+
* directly or under `build/`) wins. Otherwise the scan root and the project's
|
|
127
|
+
* build directories are searched: the directory of `options.cmakeCache`, the
|
|
128
|
+
* build directories of its CMake presets, and the conventional `build`,
|
|
129
|
+
* `out`, `builddir` and `cmake-build-` directories (see
|
|
130
|
+
* `cmakeBuildDirCandidates`). A database can come with the code it describes,
|
|
131
|
+
* and atom asks the
|
|
123
132
|
* GCC or Clang driver it names (from the PATH, or an absolute path outside
|
|
124
133
|
* the project) for its predefined macros, so in secure mode only an explicit
|
|
125
134
|
* database is used.
|
|
@@ -159,20 +168,7 @@ export function findCompileCommands(src, options = {}) {
|
|
|
159
168
|
if (!rootIsDir) {
|
|
160
169
|
return undefined;
|
|
161
170
|
}
|
|
162
|
-
const dirs = [root, ...
|
|
163
|
-
try {
|
|
164
|
-
dirs.push(
|
|
165
|
-
...readdirSync(root, { withFileTypes: true })
|
|
166
|
-
.filter((e) => e.isDirectory() && e.name.startsWith("cmake-build-"))
|
|
167
|
-
.map((e) => join(root, e.name))
|
|
168
|
-
.sort(),
|
|
169
|
-
);
|
|
170
|
-
} catch (_err) {
|
|
171
|
-
// an unreadable root has no build directories to offer
|
|
172
|
-
}
|
|
173
|
-
if (options.cmakeCache) {
|
|
174
|
-
dirs.push(dirname(resolve(`${options.cmakeCache}`)));
|
|
175
|
-
}
|
|
171
|
+
const dirs = [root, ...cmakeBuildDirCandidates(root, options)];
|
|
176
172
|
for (const dir of dirs) {
|
|
177
173
|
const candidate = join(dir, COMPILE_COMMANDS_FILE);
|
|
178
174
|
try {
|
|
@@ -319,6 +315,38 @@ export function atomCompileCommandsArgs(src, language, options = {}) {
|
|
|
319
315
|
return ["--frontend-args", `compile-commands=${database}`];
|
|
320
316
|
}
|
|
321
317
|
|
|
318
|
+
/**
|
|
319
|
+
* The arguments that stop atom's Java frontend from running the scanned
|
|
320
|
+
* project's build. In its default delombok mode, atom runs
|
|
321
|
+
* `mvn dependency:build-classpath` inside a Maven project, which loads the
|
|
322
|
+
* project's `.mvn` configuration and build extensions, so delombok and
|
|
323
|
+
* dependency fetching are turned off whenever the project's own tooling may
|
|
324
|
+
* not run.
|
|
325
|
+
*
|
|
326
|
+
* @param {string} language atom `-l` value
|
|
327
|
+
* @param {Object} options CLI options
|
|
328
|
+
* @returns {string[]|undefined} Arguments to add to the atom command, or
|
|
329
|
+
* undefined when the installed atom cannot be told to leave the build alone
|
|
330
|
+
*/
|
|
331
|
+
export function atomBuildToolArgs(language, options = {}) {
|
|
332
|
+
if (
|
|
333
|
+
`${language}`.toLowerCase() !== "java" ||
|
|
334
|
+
isProjectToolingAllowed(options)
|
|
335
|
+
) {
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
const keys = atomFrontendArgKeys(language);
|
|
339
|
+
if (!keys.has("delombok-mode")) {
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
return [
|
|
343
|
+
"--frontend-args",
|
|
344
|
+
keys.has("fetch-dependencies")
|
|
345
|
+
? "delombok-mode=no-delombok,fetch-dependencies=false"
|
|
346
|
+
: "delombok-mode=no-delombok",
|
|
347
|
+
];
|
|
348
|
+
}
|
|
349
|
+
|
|
322
350
|
// Absolute ceiling on atom's heap. Past this point a larger heap buys a
|
|
323
351
|
// collector that runs less often rather than an analysis that succeeds where it
|
|
324
352
|
// otherwise would not, while the reservation itself is what pushes a build
|
|
@@ -751,18 +779,32 @@ export function buildAtomCommandEnv(options = {}, language = "") {
|
|
|
751
779
|
// that does not exist on native platforms, and atom 3.0.x crashes parsing
|
|
752
780
|
// that bogus value. Forward the resolved php-parse location through the env
|
|
753
781
|
// so executeAtom can bypass the dispatcher for PHP (see
|
|
754
|
-
// resolveDirectAtomBinaryPath).
|
|
782
|
+
// resolveDirectAtomBinaryPath). PHP_ASTGEN_BIN additionally names the
|
|
783
|
+
// batch-capable generator (phpastgen.js): chen parses the whole tree, vendor
|
|
784
|
+
// included, in one generator run instead of one php interpreter per file,
|
|
785
|
+
// which on windows is the difference between minutes and hours. Computed
|
|
786
|
+
// independently of exclude patterns.
|
|
755
787
|
const phpParseBin = ATOM_PHP_LANGUAGES.has(normalizedLanguage)
|
|
756
788
|
? resolvePhpParseBin()
|
|
757
789
|
: undefined;
|
|
790
|
+
const phpAstgenBin = ATOM_PHP_LANGUAGES.has(normalizedLanguage)
|
|
791
|
+
? resolvePhpAstgenBin()
|
|
792
|
+
: undefined;
|
|
793
|
+
const phpEnv = {};
|
|
794
|
+
if (phpParseBin) {
|
|
795
|
+
phpEnv.PHP_PARSER_BIN = phpParseBin;
|
|
796
|
+
}
|
|
797
|
+
if (phpAstgenBin) {
|
|
798
|
+
phpEnv.PHP_ASTGEN_BIN = phpAstgenBin;
|
|
799
|
+
}
|
|
758
800
|
if (!excludePatterns.length) {
|
|
759
|
-
return
|
|
801
|
+
return phpEnv;
|
|
760
802
|
}
|
|
761
803
|
const chenIgnoreDirs = mergeCsvValues(
|
|
762
804
|
readEnvironmentVariable("CHEN_IGNORE_DIRS"),
|
|
763
805
|
extractIgnoreDirsFromExcludePatterns(excludePatterns, true),
|
|
764
806
|
);
|
|
765
|
-
const env = {};
|
|
807
|
+
const env = { ...phpEnv };
|
|
766
808
|
if (chenIgnoreDirs) {
|
|
767
809
|
env.CHEN_IGNORE_DIRS = chenIgnoreDirs;
|
|
768
810
|
}
|
|
@@ -788,9 +830,6 @@ export function buildAtomCommandEnv(options = {}, language = "") {
|
|
|
788
830
|
env.ASTGEN_IGNORE_FILE_PATTERN = astgenIgnoreFilePattern;
|
|
789
831
|
}
|
|
790
832
|
}
|
|
791
|
-
if (phpParseBin) {
|
|
792
|
-
env.PHP_PARSER_BIN = phpParseBin;
|
|
793
|
-
}
|
|
794
833
|
return env;
|
|
795
834
|
}
|
|
796
835
|
|
|
@@ -880,15 +919,19 @@ export function resolveAtomProvider(opts = {}) {
|
|
|
880
919
|
* ceiling differently, and a native-image runtime option on a jar run reaches
|
|
881
920
|
* atom as an unknown argument that fails every slice. So the kind follows what
|
|
882
921
|
* is installed where cdxgen can see it: the native binary means native, the jar
|
|
883
|
-
* package without it means jar.
|
|
884
|
-
* install elsewhere) the
|
|
922
|
+
* package without it means jar. An `ATOM_CMD` is classified by what it names
|
|
923
|
+
* (see `atomCommandKind`). With nothing in view (an install elsewhere) the
|
|
924
|
+
* platform's kind stands.
|
|
885
925
|
*
|
|
886
926
|
* Also used to gate Java/JDK advice, so users on the five native platforms are
|
|
887
927
|
* not told to install a JDK for a failure that has nothing to do with Java.
|
|
888
928
|
*/
|
|
889
929
|
export function atomProviderKind() {
|
|
890
930
|
const { kind } = resolveAtomProvider();
|
|
891
|
-
if (
|
|
931
|
+
if (readEnvironmentVariable("ATOM_CMD")) {
|
|
932
|
+
return atomCommandKind(readEnvironmentVariable("ATOM_CMD"), kind);
|
|
933
|
+
}
|
|
934
|
+
if (kind !== "native") {
|
|
892
935
|
return kind;
|
|
893
936
|
}
|
|
894
937
|
const atomHome = readEnvironmentVariable("ATOM_HOME");
|
|
@@ -906,13 +949,64 @@ export function atomProviderKind() {
|
|
|
906
949
|
return jarPlugins ? "jar" : kind;
|
|
907
950
|
}
|
|
908
951
|
|
|
952
|
+
/**
|
|
953
|
+
* Whether `ATOM_CMD` launches a jar or follows the platform.
|
|
954
|
+
*
|
|
955
|
+
* The jar launchers (`plugins/bin/atom`, `plugins/bin/atom.bat`) sit next to a
|
|
956
|
+
* `plugins/lib` directory holding atom's jars, so a launcher with that sibling,
|
|
957
|
+
* or any `.bat` (only the jar payload ships one), runs on the JVM whatever the
|
|
958
|
+
* platform is. Everything else, including the npm dispatcher (`node
|
|
959
|
+
* .../index.js`, its `atom`/`atom.cmd` bin shims) and a native binary, follows
|
|
960
|
+
* the platform's kind. A GraalVM `-XX:` heap argument handed to a jar launcher
|
|
961
|
+
* is rejected by atom's option parser before any analysis starts, and a
|
|
962
|
+
* `JAVA_TOOL_OPTIONS` ceiling handed to a native image is silently ignored, so
|
|
963
|
+
* the distinction decides whether the heap is bounded at all.
|
|
964
|
+
*
|
|
965
|
+
* @param {string} command The `ATOM_CMD` value
|
|
966
|
+
* @param {"native"|"jar"} platformKind Kind the platform prefers
|
|
967
|
+
* @returns {"native"|"jar"}
|
|
968
|
+
*/
|
|
969
|
+
export function atomCommandKind(command, platformKind) {
|
|
970
|
+
const [bin, leadingArg] = splitAtomCommand(command);
|
|
971
|
+
const runsScript =
|
|
972
|
+
leadingArg !== undefined && /^node(\.exe)?$/i.test(basename(bin));
|
|
973
|
+
let launcher = runsScript ? leadingArg : bin;
|
|
974
|
+
if (/\.bat$/i.test(launcher)) {
|
|
975
|
+
return "jar";
|
|
976
|
+
}
|
|
977
|
+
try {
|
|
978
|
+
// npm bin entries are symlinks into the package (`/usr/local/bin/atom` ->
|
|
979
|
+
// `.../@appthreat/atom/index.js`), and `/usr/local` has a `lib` of its own.
|
|
980
|
+
launcher = realpathSync(launcher);
|
|
981
|
+
} catch {
|
|
982
|
+
return platformKind;
|
|
983
|
+
}
|
|
984
|
+
const binDir = dirname(launcher);
|
|
985
|
+
if (basename(binDir) !== "bin") {
|
|
986
|
+
return platformKind;
|
|
987
|
+
}
|
|
988
|
+
try {
|
|
989
|
+
const libDir = join(dirname(binDir), "lib");
|
|
990
|
+
if (
|
|
991
|
+
readdirSync(libDir).some(
|
|
992
|
+
(file) => file.startsWith("io.appthreat.atom") && file.endsWith(".jar"),
|
|
993
|
+
)
|
|
994
|
+
) {
|
|
995
|
+
return "jar";
|
|
996
|
+
}
|
|
997
|
+
} catch {
|
|
998
|
+
// no lib directory: not a jar layout
|
|
999
|
+
}
|
|
1000
|
+
return platformKind;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
909
1003
|
/**
|
|
910
1004
|
* Locate the `php-parse` binary that the PHP frontend needs.
|
|
911
1005
|
*
|
|
912
1006
|
* atom 3's dispatcher unconditionally sets `PHP_PARSER_BIN=<ATOM_HOME>/bin/php-parse`,
|
|
913
1007
|
* which for a native sub-package does not exist and also clobbers a caller-set
|
|
914
|
-
* value. cdxgen therefore resolves the real location and forwards it through
|
|
915
|
-
*
|
|
1008
|
+
* value. cdxgen therefore resolves the real location and forwards it through the
|
|
1009
|
+
* child env (see `buildAtomCommandEnv`); `executeAtom` then spawns the
|
|
916
1010
|
* native binary directly for PHP so the dispatcher cannot clobber it (see
|
|
917
1011
|
* `resolveDirectAtomBinaryPath`). Resolution order:
|
|
918
1012
|
* 1. explicit `PHP_PARSER_BIN` env var (operators / container images)
|
|
@@ -929,6 +1023,44 @@ export function resolvePhpParseBin() {
|
|
|
929
1023
|
if (readEnvironmentVariable("PHP_PARSER_BIN")) {
|
|
930
1024
|
return readEnvironmentVariable("PHP_PARSER_BIN");
|
|
931
1025
|
}
|
|
1026
|
+
return parsetoolsFile("plugins", "bin", "php-parse");
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Locate the `phpastgen` generator that lets the PHP frontend parse whole
|
|
1031
|
+
* directories in one batch.
|
|
1032
|
+
*
|
|
1033
|
+
* `php-parse` (forwarded as `PHP_PARSER_BIN`) is the per-file parser: atom
|
|
1034
|
+
* starts a php interpreter for every `.php` file, which on windows turns a
|
|
1035
|
+
* vendored PHP project (thousands of files under `vendor/`) into an hours-long
|
|
1036
|
+
* run that no timeout can rescue. `phpastgen` answers the `--parser-info`
|
|
1037
|
+
* capability probe, so atom's batch path engages, and atom-parsetools 1.9 and
|
|
1038
|
+
* later parse the whole tree, vendor included, with a few interpreters that
|
|
1039
|
+
* each take a chunk of files. It is a Node script, so the frontend launches it
|
|
1040
|
+
* with `node` rather than `php`; an atom that does not know `PHP_ASTGEN_BIN`
|
|
1041
|
+
* simply ignores it and keeps today's per-file behaviour. Resolution order:
|
|
1042
|
+
* 1. explicit `PHP_ASTGEN_BIN` env var (operators / container images)
|
|
1043
|
+
* 2. `@appthreat/atom-parsetools/phpastgen.js` under cdxgen's own
|
|
1044
|
+
* node_modules, then under `GLOBAL_NODE_MODULES_PATH` for global installs
|
|
1045
|
+
*
|
|
1046
|
+
* @returns {string|undefined}
|
|
1047
|
+
*/
|
|
1048
|
+
export function resolvePhpAstgenBin() {
|
|
1049
|
+
if (readEnvironmentVariable("PHP_ASTGEN_BIN")) {
|
|
1050
|
+
return readEnvironmentVariable("PHP_ASTGEN_BIN");
|
|
1051
|
+
}
|
|
1052
|
+
return parsetoolsFile("phpastgen.js");
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* Resolve a file inside the installed `@appthreat/atom-parsetools` package,
|
|
1057
|
+
* searching cdxgen's own node_modules and `GLOBAL_NODE_MODULES_PATH` for global
|
|
1058
|
+
* installs.
|
|
1059
|
+
*
|
|
1060
|
+
* @param {...string} segments Path segments below the package root
|
|
1061
|
+
* @returns {string|undefined}
|
|
1062
|
+
*/
|
|
1063
|
+
export function parsetoolsFile(...segments) {
|
|
932
1064
|
const roots = [dirNameStr];
|
|
933
1065
|
if (readEnvironmentVariable("GLOBAL_NODE_MODULES_PATH")) {
|
|
934
1066
|
roots.push(dirname(readEnvironmentVariable("GLOBAL_NODE_MODULES_PATH")));
|
|
@@ -939,9 +1071,7 @@ export function resolvePhpParseBin() {
|
|
|
939
1071
|
"node_modules",
|
|
940
1072
|
"@appthreat",
|
|
941
1073
|
"atom-parsetools",
|
|
942
|
-
|
|
943
|
-
"bin",
|
|
944
|
-
"php-parse",
|
|
1074
|
+
...segments,
|
|
945
1075
|
);
|
|
946
1076
|
if (safeExistsSync(candidate)) {
|
|
947
1077
|
return candidate;
|
|
@@ -1213,25 +1343,41 @@ export function atomTimeouts() {
|
|
|
1213
1343
|
};
|
|
1214
1344
|
}
|
|
1215
1345
|
|
|
1216
|
-
function formatDuration(ms) {
|
|
1217
|
-
if (ms >= 60_000) {
|
|
1218
|
-
const minutes = Math.round(ms / 6_000) / 10;
|
|
1219
|
-
return `${minutes} minute${minutes === 1 ? "" : "s"}`;
|
|
1220
|
-
}
|
|
1221
|
-
return `${Math.round(ms / 100) / 10} seconds`;
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
1346
|
// The status the atom dispatcher exits with when ATOM_TIMEOUT stops atom.
|
|
1225
1347
|
const ATOM_TIMEOUT_EXIT_CODE = 124;
|
|
1226
1348
|
|
|
1349
|
+
/**
|
|
1350
|
+
* Reap everything a timed-out atom run left behind on Windows.
|
|
1351
|
+
*
|
|
1352
|
+
* cdxgen starts atom through a shell there (`shell: isWin`), so the spawn
|
|
1353
|
+
* timeout terminates only that `cmd.exe`, and the runtime and every parser
|
|
1354
|
+
* worker under it (one `php.exe` per file for the per-file PHP frontend) keep
|
|
1355
|
+
* running against the next slice of the same run. See
|
|
1356
|
+
* {@link reapProcessTree} for how they are found. A chain broken by an
|
|
1357
|
+
* intermediate that already exited (the npm dispatcher stopping its runtime
|
|
1358
|
+
* itself) cannot be followed, and atom 4 stops its helpers once
|
|
1359
|
+
* `ATOM_PARENT_PID` is gone.
|
|
1360
|
+
*
|
|
1361
|
+
* @param {number|undefined} rootPid pid of the process cdxgen spawned
|
|
1362
|
+
* @param {number} startedAt Epoch milliseconds at which the run started
|
|
1363
|
+
* @param {number} [endedAt] Epoch milliseconds at which the spawned process ended
|
|
1364
|
+
* @returns {number[]} The pids that were stopped
|
|
1365
|
+
*/
|
|
1366
|
+
export function reapAtomProcessTree(rootPid, startedAt, endedAt = Date.now()) {
|
|
1367
|
+
return reapProcessTree(rootPid, startedAt, endedAt, "atom");
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1227
1370
|
/**
|
|
1228
1371
|
* Whether an atom run ended because it ran out of time.
|
|
1229
1372
|
*
|
|
1230
1373
|
* The dispatcher reports its own limit with status 124. cdxgen's spawn timeout
|
|
1231
1374
|
* shows up as `ETIMEDOUT`. A dispatcher older than the status code stops atom
|
|
1232
|
-
* with SIGTERM and
|
|
1233
|
-
*
|
|
1234
|
-
*
|
|
1375
|
+
* with SIGTERM and passes on how the runtime ended: 1, or the runtime's own
|
|
1376
|
+
* exit on SIGTERM (143) or SIGKILL (137), which is what atom 3.1 reports. Those
|
|
1377
|
+
* statuses at or past the limit count as well, unless atom's own output shows
|
|
1378
|
+
* it failed for another reason first (an exhausted heap, a crash), which
|
|
1379
|
+
* deserves its own diagnosis. Missing one leaves the half-written atom behind,
|
|
1380
|
+
* and the next slice of the run fails to load it.
|
|
1235
1381
|
*
|
|
1236
1382
|
* @param {Object} result spawnSync result
|
|
1237
1383
|
* @param {number} elapsedMs How long the run took
|
|
@@ -1245,13 +1391,21 @@ export function atomRunTimedOut(result, elapsedMs, atomTimeoutMs) {
|
|
|
1245
1391
|
if (result?.error?.code === "ETIMEDOUT") {
|
|
1246
1392
|
return true;
|
|
1247
1393
|
}
|
|
1248
|
-
if (
|
|
1394
|
+
if (
|
|
1395
|
+
!ATOM_STOPPED_STATUSES.includes(result?.status) ||
|
|
1396
|
+
elapsedMs < atomTimeoutMs
|
|
1397
|
+
) {
|
|
1249
1398
|
return false;
|
|
1250
1399
|
}
|
|
1251
1400
|
const output = `${result.stdout || ""}\n${result.stderr || ""}`;
|
|
1252
1401
|
return !ATOM_FAILURE_MARKERS.some((marker) => output.includes(marker));
|
|
1253
1402
|
}
|
|
1254
1403
|
|
|
1404
|
+
// How a runtime stopped by an older dispatcher at ATOM_TIMEOUT exits: the
|
|
1405
|
+
// dispatcher's own 1, or the runtime's exit on SIGTERM (128 + 15) or SIGKILL
|
|
1406
|
+
// (128 + 9) passed through.
|
|
1407
|
+
const ATOM_STOPPED_STATUSES = [1, 137, 143];
|
|
1408
|
+
|
|
1255
1409
|
// Output that means atom failed by itself, whatever the clock says.
|
|
1256
1410
|
const ATOM_FAILURE_MARKERS = [
|
|
1257
1411
|
"OutOfMemoryError",
|
|
@@ -1350,10 +1504,12 @@ export function executeAtom(src, args, extra_env = {}) {
|
|
|
1350
1504
|
env,
|
|
1351
1505
|
timeout: spawnTimeoutMs,
|
|
1352
1506
|
});
|
|
1353
|
-
|
|
1507
|
+
const endedAt = Date.now();
|
|
1508
|
+
if (atomRunTimedOut(result, endedAt - startedAt, atomTimeoutMs)) {
|
|
1354
1509
|
console.warn(
|
|
1355
1510
|
`WARN: atom did not finish within ${formatDuration(atomTimeoutMs)} and was stopped, so its results are missing or incomplete. Allow more time with ATOM_TIMEOUT (milliseconds, atom only) or CDXGEN_TIMEOUT_MS (every external command).`,
|
|
1356
1511
|
);
|
|
1512
|
+
reapAtomProcessTree(result.pid, startedAt, endedAt);
|
|
1357
1513
|
// A stopped atom leaves its graph half written, and the next slice of the
|
|
1358
1514
|
// same run would try to reuse it and fail to load it.
|
|
1359
1515
|
const atomFileIndex = args.indexOf("-o");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { shouldRunPredictiveBomAudit } from "../core/env.js";
|
|
1
|
+
import { getCommandName, shouldRunPredictiveBomAudit } from "../core/env.js";
|
|
2
2
|
|
|
3
3
|
/** Frozen list of hardware-bill-of-materials (HBOM) audit categories. */
|
|
4
4
|
export const HBOM_AUDIT_CATEGORIES = Object.freeze([
|
|
@@ -23,6 +23,12 @@ export const GOLEM_AUDIT_CATEGORIES = Object.freeze([
|
|
|
23
23
|
"golem-compliance",
|
|
24
24
|
]);
|
|
25
25
|
|
|
26
|
+
/** Frozen list of Scala Evinse (scalasem) audit categories. */
|
|
27
|
+
export const SCALA_AUDIT_CATEGORIES = Object.freeze([
|
|
28
|
+
"scala-security",
|
|
29
|
+
"scala-compliance",
|
|
30
|
+
]);
|
|
31
|
+
|
|
26
32
|
/** Frozen list of Cargo (Rust) audit categories. */
|
|
27
33
|
export const CARGO_AUDIT_CATEGORIES = Object.freeze([
|
|
28
34
|
"cargo-security",
|
|
@@ -64,6 +70,7 @@ export const BOM_AUDIT_CATEGORY_ALIASES = Object.freeze({
|
|
|
64
70
|
golem: [...GOLEM_AUDIT_CATEGORIES],
|
|
65
71
|
hbom: [...HBOM_AUDIT_CATEGORIES],
|
|
66
72
|
rust: [...CARGO_AUDIT_CATEGORIES],
|
|
73
|
+
scala: [...SCALA_AUDIT_CATEGORIES],
|
|
67
74
|
host: [...HBOM_AUDIT_CATEGORIES, ...HOST_TOPOLOGY_AUDIT_CATEGORIES],
|
|
68
75
|
});
|
|
69
76
|
|
|
@@ -179,11 +186,11 @@ export function validateBomAuditCategories(categories, rules) {
|
|
|
179
186
|
* @returns {string | undefined} Default category string, if any
|
|
180
187
|
*/
|
|
181
188
|
export function getDefaultBomAuditCategories(options, commandPath) {
|
|
182
|
-
const
|
|
189
|
+
const commandName = getCommandName(commandPath);
|
|
183
190
|
const defaultHbomCategories = options?.includeRuntime
|
|
184
191
|
? `${DEFAULT_HBOM_AUDIT_CATEGORIES},host-topology`
|
|
185
192
|
: DEFAULT_HBOM_AUDIT_CATEGORIES;
|
|
186
|
-
if (
|
|
193
|
+
if (commandName.startsWith("hbom")) {
|
|
187
194
|
return defaultHbomCategories;
|
|
188
195
|
}
|
|
189
196
|
const projectTypes = Array.isArray(options?.projectType)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { recordDegradation } from "../core/buildLedger.js";
|
|
2
|
+
import { registerRunReset } from "../core/runState.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Text a build tool prints when its Maven repository answers HTTP 429, as
|
|
6
|
+
* recorded from each tool against a repository that rate limits. One small
|
|
7
|
+
* matcher per tool, plain substring tests on the combined output: the tools
|
|
8
|
+
* reword their messages between versions, so the matched fragment is the one
|
|
9
|
+
* every observed phrasing keeps (the status number in the tool's own wording).
|
|
10
|
+
*
|
|
11
|
+
* sbt, Mill and scala-cli resolve through Coursier, so they share the
|
|
12
|
+
* coursier matcher. The Coursier inside sbt 1.x reports the JDK's
|
|
13
|
+
* `Server returned HTTP response code: 429`; the one in sbt 2, Mill and
|
|
14
|
+
* scala-cli reports `retryable HTTP error: <url> (HTTP 429)`, with a
|
|
15
|
+
* `Retry-After` inside the parentheses when the server sent one.
|
|
16
|
+
*
|
|
17
|
+
* @type {Object<string, string[]>}
|
|
18
|
+
*/
|
|
19
|
+
const RATE_LIMIT_MARKERS = {
|
|
20
|
+
maven: ["status code: 429", "Too Many Requests"],
|
|
21
|
+
gradle: ["Received status code 429", "[HTTP 429: http"],
|
|
22
|
+
coursier: ["response code: 429", "(HTTP 429"],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The matcher family a tool belongs to.
|
|
27
|
+
*
|
|
28
|
+
* @type {Object<string, string>}
|
|
29
|
+
*/
|
|
30
|
+
const TOOL_MATCHER = {
|
|
31
|
+
maven: "maven",
|
|
32
|
+
gradle: "gradle",
|
|
33
|
+
sbt: "coursier",
|
|
34
|
+
mill: "coursier",
|
|
35
|
+
"scala-cli": "coursier",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* How each tool is moved to a mirror, named in one hint per tool and scan.
|
|
40
|
+
* sbt reads its own repositories file; Mill and scala-cli read Coursier's
|
|
41
|
+
* mirror.properties, whose entry spells the semicolon-separated format
|
|
42
|
+
* because a comma list is silently ignored.
|
|
43
|
+
*
|
|
44
|
+
* @type {Object<string, string>}
|
|
45
|
+
*/
|
|
46
|
+
const MIRROR_SETTINGS = {
|
|
47
|
+
maven:
|
|
48
|
+
"Point Maven at a mirror with a <mirror> entry in the Maven settings.xml, or set MVNW_REPOURL for the Maven wrapper.",
|
|
49
|
+
gradle:
|
|
50
|
+
"Point Gradle at a mirror by declaring the repository in a Gradle init script.",
|
|
51
|
+
sbt: "Point sbt at a mirror by listing it in ~/.sbt/repositories and passing -Dsbt.override.build.repos=true in SBT_OPTS or .sbtopts.",
|
|
52
|
+
coursier:
|
|
53
|
+
"Point Coursier at a mirror with mirror.properties, setting central.from and central.to (separate several central.from URLs with semicolons, not commas).",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Tools whose later invocations or retries cdxgen skips once one met a rate
|
|
58
|
+
* limit. Mill and scala-cli resolve in a single invocation.
|
|
59
|
+
*
|
|
60
|
+
* @type {Set<string>}
|
|
61
|
+
*/
|
|
62
|
+
const STOPPED_TOOLS = new Set(["maven", "gradle", "sbt"]);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Tools whose repository answered HTTP 429 during the current scan. Further
|
|
66
|
+
* invocations of that tool would only pay the same back-off for the same
|
|
67
|
+
* empty answer.
|
|
68
|
+
*
|
|
69
|
+
* @type {Set<string>}
|
|
70
|
+
*/
|
|
71
|
+
const rateLimitedTools = new Set();
|
|
72
|
+
|
|
73
|
+
registerRunReset("inventory.buildToolRateLimit", () => {
|
|
74
|
+
rateLimitedTools.clear();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Whether a tool's combined output names a rate limit from its repository.
|
|
79
|
+
* The answer text is treated as untrusted: only fixed substrings are looked
|
|
80
|
+
* for, nothing from the output is kept.
|
|
81
|
+
*
|
|
82
|
+
* @param {string} output Combined stdout and stderr of one invocation.
|
|
83
|
+
* @param {string} tool One of maven, gradle, sbt, mill, scala-cli.
|
|
84
|
+
* @returns {boolean} True when the output names an HTTP 429 answer.
|
|
85
|
+
*/
|
|
86
|
+
export function detectBuildToolRateLimit(output, tool) {
|
|
87
|
+
const markers = RATE_LIMIT_MARKERS[TOOL_MATCHER[tool]];
|
|
88
|
+
if (!markers || typeof output !== "string" || !output) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return markers.some((marker) => output.includes(marker));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Whether a tool was already found rate limited in this scan, so the caller
|
|
96
|
+
* can skip its remaining invocations.
|
|
97
|
+
*
|
|
98
|
+
* @param {string} tool One of maven, gradle, sbt, mill, scala-cli.
|
|
99
|
+
* @returns {boolean}
|
|
100
|
+
*/
|
|
101
|
+
export function isBuildToolRateLimited(tool) {
|
|
102
|
+
return rateLimitedTools.has(tool);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Read a completed invocation's output for a rate limit. When one is found,
|
|
107
|
+
* the tool is remembered for the scan, one hint naming the tool's mirror
|
|
108
|
+
* setting is printed, and the `build.rate-limited` degradation is recorded.
|
|
109
|
+
* The first invocation that shows the rate limit is the one recorded; later
|
|
110
|
+
* ones add nothing, because the same answer ends them all.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} tool One of maven, gradle, sbt, mill, scala-cli.
|
|
113
|
+
* @param {string|undefined} output Combined output, as commandOutputText
|
|
114
|
+
* returns it for a spawn result.
|
|
115
|
+
* @param {Object} [context] Call-site facts for the degradation event.
|
|
116
|
+
* @param {string} [context.command] The redacted command that was attempted.
|
|
117
|
+
* @param {number} [context.exitCode] The invocation's exit status.
|
|
118
|
+
* @returns {boolean} True when this output names a rate limit.
|
|
119
|
+
*/
|
|
120
|
+
export function noteBuildToolRateLimit(tool, output, context = {}) {
|
|
121
|
+
if (!detectBuildToolRateLimit(output, tool)) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
if (isBuildToolRateLimited(tool)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
rateLimitedTools.add(tool);
|
|
128
|
+
const stopped = STOPPED_TOOLS.has(tool)
|
|
129
|
+
? `, so cdxgen runs no further ${tool} resolution in this scan and`
|
|
130
|
+
: ", so";
|
|
131
|
+
console.warn(
|
|
132
|
+
`The repository ${tool} downloads from is rate limiting this machine (HTTP 429)${stopped} its dependency tree is incomplete. ${MIRROR_SETTINGS[tool] || MIRROR_SETTINGS[TOOL_MATCHER[tool]]} cdxgen's own lookups can be moved with MAVEN_CENTRAL_URL.`,
|
|
133
|
+
);
|
|
134
|
+
recordDegradation("build.rate-limited", {
|
|
135
|
+
ecosystem: "java",
|
|
136
|
+
tool,
|
|
137
|
+
impact: "transitive-deps",
|
|
138
|
+
command: context.command,
|
|
139
|
+
exitCode: context.exitCode,
|
|
140
|
+
detail: `The repository ${tool} downloads from answered HTTP 429, so ${tool} resolved no dependencies.`,
|
|
141
|
+
outputExcerpt: output,
|
|
142
|
+
});
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `cdxgen cache` subcommand — inspect and purge the metadata fetch cache
|
|
2
|
+
* `cdxgen cache` subcommand — inspect and purge the metadata fetch cache that
|
|
3
|
+
* cdxrs and the JS batch pool share.
|
|
3
4
|
*
|
|
4
5
|
* This module operates directly on the filesystem because JS is the authority
|
|
5
6
|
* for the cache directory. The cache layout is:
|
|
@@ -28,13 +28,21 @@ import { isMac, isWin } from "../core/paths.js";
|
|
|
28
28
|
* rather than reading `isWin`/`isMac` here, or the Windows and Linux branches
|
|
29
29
|
* become untestable on a macOS developer machine.
|
|
30
30
|
*
|
|
31
|
+
* Every environment-derived root must be absolute by the *target* platform's
|
|
32
|
+
* rules, never the host's (`path.isAbsolute` would accept `\cache` on a
|
|
33
|
+
* Windows host): a relative value is ignored, so it cannot point inside the
|
|
34
|
+
* working directory. XDG requires this of `XDG_CACHE_HOME`; the home and
|
|
35
|
+
* `LOCALAPPDATA` roots get the same treatment for the same reason.
|
|
36
|
+
*
|
|
31
37
|
* @param {Object} inputs Resolution inputs.
|
|
32
38
|
* @param {"linux"|"macos"|"windows"} inputs.platform Which convention to apply.
|
|
33
|
-
* @param {string} [inputs.cdxgenCacheDir] `CDXGEN_CACHE_DIR
|
|
39
|
+
* @param {string} [inputs.cdxgenCacheDir] `CDXGEN_CACHE_DIR`, an explicit
|
|
40
|
+
* override taken as given.
|
|
34
41
|
* @param {string} [inputs.xdgCacheHome] `XDG_CACHE_HOME`. Ignored unless
|
|
35
|
-
*
|
|
36
|
-
* @param {string} [inputs.home] Home directory.
|
|
37
|
-
* @param {string} [inputs.localAppData] `LOCALAPPDATA`.
|
|
42
|
+
* `/`-rooted.
|
|
43
|
+
* @param {string} [inputs.home] Home directory. Ignored unless absolute.
|
|
44
|
+
* @param {string} [inputs.localAppData] `LOCALAPPDATA`. Ignored unless drive-
|
|
45
|
+
* or UNC-rooted; the home profile is the fallback.
|
|
38
46
|
* @returns {string|null} Absolute path, or null when nothing resolves.
|
|
39
47
|
*/
|
|
40
48
|
export function resolveCacheDirFor({
|
|
@@ -48,20 +56,55 @@ export function resolveCacheDirFor({
|
|
|
48
56
|
return path.resolve(cdxgenCacheDir);
|
|
49
57
|
}
|
|
50
58
|
if (platform === "windows") {
|
|
51
|
-
if (localAppData
|
|
59
|
+
if (isWindowsAbsolute(localAppData)) {
|
|
52
60
|
return path.join(localAppData, "cdxgen", "cache");
|
|
53
61
|
}
|
|
54
|
-
return home
|
|
62
|
+
return isWindowsAbsolute(home)
|
|
55
63
|
? path.join(home, "AppData", "Local", "cdxgen", "cache")
|
|
56
64
|
: null;
|
|
57
65
|
}
|
|
58
66
|
if (platform === "macos") {
|
|
59
|
-
return
|
|
67
|
+
return isPosixAbsolute(home)
|
|
68
|
+
? path.join(home, "Library", "Caches", "cdxgen")
|
|
69
|
+
: null;
|
|
60
70
|
}
|
|
61
|
-
if (
|
|
71
|
+
if (isPosixAbsolute(xdgCacheHome)) {
|
|
62
72
|
return path.join(xdgCacheHome, "cdxgen");
|
|
63
73
|
}
|
|
64
|
-
return home
|
|
74
|
+
return isPosixAbsolute(home) ? path.join(home, ".cache", "cdxgen") : null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Absolute by POSIX rules: `/`-rooted.
|
|
79
|
+
*
|
|
80
|
+
* @param {string} [value] Candidate path
|
|
81
|
+
* @returns {boolean} Whether the path is absolute
|
|
82
|
+
*/
|
|
83
|
+
function isPosixAbsolute(value) {
|
|
84
|
+
return typeof value === "string" && value.startsWith("/");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Absolute by Windows rules: a drive letter followed by a separator (`C:\` or
|
|
89
|
+
* `C:/`), or a UNC path (`\\server\share`). `C:cache` (relative to the drive's
|
|
90
|
+
* current directory) and `\cache` (relative to the current drive) are not.
|
|
91
|
+
* Mirrors `is_windows_absolute` in cdxrs.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} [value] Candidate path
|
|
94
|
+
* @returns {boolean} Whether the path is absolute
|
|
95
|
+
*/
|
|
96
|
+
function isWindowsAbsolute(value) {
|
|
97
|
+
if (typeof value !== "string" || value.length < 3) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
const isSeparator = (char) => char === "\\" || char === "/";
|
|
101
|
+
const driveRooted = /^[a-zA-Z]$/.test(value[0]) && value[1] === ":";
|
|
102
|
+
if (driveRooted) {
|
|
103
|
+
return isSeparator(value[2]);
|
|
104
|
+
}
|
|
105
|
+
return (
|
|
106
|
+
isSeparator(value[0]) && isSeparator(value[1]) && !isSeparator(value[2])
|
|
107
|
+
);
|
|
65
108
|
}
|
|
66
109
|
|
|
67
110
|
/**
|