@cdxgen/cdxgen 0.0.1 → 13.0.1
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 +921 -87
- package/bin/audit.js +239 -0
- package/bin/cdxgen.js +2335 -0
- package/bin/convert.js +220 -0
- package/bin/evinse.js +353 -0
- package/bin/hbom.js +504 -0
- package/bin/repl.js +2224 -0
- package/bin/sign.js +195 -0
- package/bin/tracebom.js +303 -0
- package/bin/validate.js +268 -0
- package/bin/verify.js +189 -0
- package/data/README.md +307 -0
- package/data/bom-1.4.schema.json +1605 -0
- package/data/bom-1.5.schema.json +3660 -0
- package/data/bom-1.6.schema.json +5511 -0
- package/data/bom-1.7.schema.json +6700 -0
- package/data/cbomosdb-queries.json +68 -0
- package/data/component-tags.json +339 -0
- package/data/container-knowledge-index.json +125 -0
- package/data/cosdb-queries.json +17 -0
- package/data/crypto-oid.json +1998 -0
- package/data/cryptography-defs.json +3793 -0
- package/data/cryptography-defs.schema.json +576 -0
- package/data/cyclonedx-2.0-bundled.schema.json +7182 -0
- package/data/frameworks-list.json +219 -0
- package/data/glibc-stdlib.json +117 -0
- package/data/gtfobins-index.json +6296 -0
- package/data/helpers/init.gradle +71 -0
- package/data/jsf-0.82.schema.json +211 -0
- package/data/known-licenses.json +82 -0
- package/data/lic-mapping.json +338 -0
- package/data/license-aliases.json +6624 -0
- package/data/license-db.json +39059 -0
- package/data/license-deprecations.json +302 -0
- package/data/lolbas-index.json +150 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/pypi-pkg-aliases.json +1199 -0
- package/data/python-stdlib.json +308 -0
- package/data/queries-darwin.json +193 -0
- package/data/queries-win.json +257 -0
- package/data/queries.json +268 -0
- package/data/ruby-known-modules.json +281 -0
- package/data/rules/ai-agent-governance.yaml +323 -0
- package/data/rules/ai-bom.yaml +268 -0
- package/data/rules/ai-oversight.yaml +186 -0
- package/data/rules/ai-provenance.yaml +92 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/cbom-security.yaml +165 -0
- package/data/rules/chrome-extensions.yaml +248 -0
- package/data/rules/ci-permissions.yaml +802 -0
- package/data/rules/container-risk.yaml +353 -0
- package/data/rules/dependency-sources.yaml +236 -0
- package/data/rules/golem-go.yaml +229 -0
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +388 -0
- package/data/rules/obom-runtime.yaml +1776 -0
- package/data/rules/package-integrity.yaml +364 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +237 -0
- package/data/spdx-export.schema.json +6794 -0
- package/data/spdx-license-list.json +7449 -0
- package/data/spdx-licenses.json +759 -0
- package/data/spdx.schema.json +819 -0
- package/data/templates/README.md +3 -0
- package/data/templates/asvs-4.0.3.cdx.json +2943 -0
- package/data/templates/asvs-5.0.cdx.json +3046 -0
- package/data/templates/bsimm-v13.cdx.json +1008 -0
- package/data/templates/masvs-2.0.0.cdx.json +225 -0
- package/data/templates/nist-ssdf-1.1.cdx.json +828 -0
- package/data/templates/pcissc-secure-slc-1.1.cdx.json +1027 -0
- package/data/templates/scvs-1.0.0.cdx.json +813 -0
- package/data/templates/ssaf-DRAFT-2023-11.cdx.json +127 -0
- package/data/vendor-alias.json +41967 -0
- package/data/wrapdb-releases.json +4227 -0
- package/index.cjs +15 -0
- package/lib/audit/index.js +2800 -0
- package/lib/audit/progress.js +114 -0
- package/lib/audit/reporters.js +937 -0
- package/lib/audit/scoring.js +560 -0
- package/lib/audit/targets.js +798 -0
- package/lib/cli/bomAssembly.js +1882 -0
- package/lib/cli/cliOptions.js +543 -0
- package/lib/cli/index.js +2759 -0
- package/lib/cli/jsBom.js +2087 -0
- package/lib/cli/jvmBom.js +1858 -0
- package/lib/cli/managedBom.js +2083 -0
- package/lib/cli/nativeBom.js +2125 -0
- package/lib/core/activity.js +1087 -0
- package/lib/core/env.js +719 -0
- package/lib/core/fs.js +1058 -0
- package/lib/core/httpClient.js +730 -0
- package/lib/core/logger.js +280 -0
- package/lib/core/parallel.js +323 -0
- package/lib/core/paths.js +70 -0
- package/lib/core/projectConfig.js +122 -0
- package/lib/core/propertySanitizer.js +174 -0
- package/lib/core/spdx.js +5 -0
- package/lib/core/state.js +59 -0
- package/lib/core/text.js +207 -0
- package/lib/core/ui.js +920 -0
- package/lib/core/urls.js +84 -0
- package/lib/ecosystems/asarutils.js +1636 -0
- package/lib/ecosystems/bunutils.js +402 -0
- package/lib/ecosystems/caxa.js +77 -0
- package/lib/ecosystems/chromextutils.js +1174 -0
- package/lib/ecosystems/cmakeResolver.js +587 -0
- package/lib/ecosystems/cppEvidence.js +305 -0
- package/lib/ecosystems/denoutils.js +1094 -0
- package/lib/ecosystems/dotnetutils.js +132 -0
- package/lib/ecosystems/ecosystems.js +2772 -0
- package/lib/ecosystems/golem.js +1807 -0
- package/lib/ecosystems/gradleutils.js +1048 -0
- package/lib/ecosystems/jsEvidence.js +317 -0
- package/lib/ecosystems/npmutils.js +586 -0
- package/lib/ecosystems/parsers-bazel.js +875 -0
- package/lib/ecosystems/parsers-dotnet.js +1430 -0
- package/lib/ecosystems/parsers-gleam.js +302 -0
- package/lib/ecosystems/parsers-go.js +818 -0
- package/lib/ecosystems/parsers-js.js +4222 -0
- package/lib/ecosystems/parsers-jvm.js +948 -0
- package/lib/ecosystems/parsers-misc.js +3191 -0
- package/lib/ecosystems/parsers-python.js +2070 -0
- package/lib/ecosystems/parsers-rust.js +1294 -0
- package/lib/ecosystems/parsers-zig.js +861 -0
- package/lib/ecosystems/pep770.js +341 -0
- package/lib/ecosystems/pylockutils.js +427 -0
- package/lib/ecosystems/pythonutils.js +1281 -0
- package/lib/ecosystems/registryProvenance.js +1003 -0
- package/lib/ecosystems/remote/huggingface.js +1343 -0
- package/lib/ecosystems/rubyutils.js +1629 -0
- package/lib/ecosystems/rusi.js +820 -0
- package/lib/ecosystems/sbtutils.js +972 -0
- package/lib/ecosystems/tea.js +607 -0
- package/lib/ecosystems/utils.js +583 -0
- package/lib/ecosystems/zigResolver.js +410 -0
- package/lib/evinser/db.js +145 -0
- package/lib/evinser/evinser.js +2362 -0
- package/lib/evinser/scalasem.js +65 -0
- package/lib/evinser/swiftsem.js +767 -0
- package/lib/helpers/annotationFormatter.js +84 -0
- package/lib/helpers/bomSigner.js +312 -0
- package/lib/helpers/exportUtils.js +160 -0
- package/lib/helpers/remote/dependency-track.js +117 -0
- package/lib/helpers/versutils.js +202 -0
- package/lib/helpers/vsixutils.js +1069 -0
- package/lib/inventory/agentFormulationParser.js +322 -0
- package/lib/inventory/aiCollector.js +2140 -0
- package/lib/inventory/aiInventory.js +414 -0
- package/lib/inventory/aiModelVariants.js +121 -0
- package/lib/inventory/aiOversightCollector.js +661 -0
- package/lib/inventory/aiProvenanceCollector.js +822 -0
- package/lib/inventory/analyzer.js +6089 -0
- package/lib/inventory/analyzerScope.js +807 -0
- package/lib/inventory/astWorker.js +20 -0
- package/lib/inventory/atomUtils.js +1092 -0
- package/lib/inventory/auditCategories.js +192 -0
- package/lib/inventory/bomUtils.js +369 -0
- package/lib/inventory/cacheCommands.js +182 -0
- package/lib/inventory/cacheDir.js +104 -0
- package/lib/inventory/cbomutils.js +590 -0
- package/lib/inventory/cdxrs.js +434 -0
- package/lib/inventory/ciParsers/azurePipelines.js +295 -0
- package/lib/inventory/ciParsers/circleCi.js +286 -0
- package/lib/inventory/ciParsers/common.js +24 -0
- package/lib/inventory/ciParsers/githubActions.js +2434 -0
- package/lib/inventory/ciParsers/gitlabCi.js +213 -0
- package/lib/inventory/ciParsers/jenkins.js +180 -0
- package/lib/inventory/citations.js +234 -0
- package/lib/inventory/communityAiConfigParser.js +756 -0
- package/lib/inventory/containerRisk.js +204 -0
- package/lib/inventory/cryptoAlgorithmFamily.js +258 -0
- package/lib/inventory/deps.js +807 -0
- package/lib/inventory/depsUtils.js +588 -0
- package/lib/inventory/display.js +2128 -0
- package/lib/inventory/dosai.js +601 -0
- package/lib/inventory/dosaiParsers.js +154 -0
- package/lib/inventory/dynamic.js +145 -0
- package/lib/inventory/envcontext.js +1793 -0
- package/lib/inventory/evidenceUtils.js +774 -0
- package/lib/inventory/fetchBatch.js +779 -0
- package/lib/inventory/fetchRate.js +255 -0
- package/lib/inventory/forgeEnricher.js +300 -0
- package/lib/inventory/formulationParsers.js +422 -0
- package/lib/inventory/gtfobins.js +339 -0
- package/lib/inventory/hbom.js +719 -0
- package/lib/inventory/hbomAnalysis.js +310 -0
- package/lib/inventory/hbomLoader.js +35 -0
- package/lib/inventory/hostTopology.js +835 -0
- package/lib/inventory/inventoryStats.js +100 -0
- package/lib/inventory/jsonLike.js +121 -0
- package/lib/inventory/licenseEnhancer.js +918 -0
- package/lib/inventory/lolbas.js +285 -0
- package/lib/inventory/mcp.js +253 -0
- package/lib/inventory/mcpConfigParser.js +683 -0
- package/lib/inventory/mcpDiscovery.js +112 -0
- package/lib/inventory/mcpPinning.js +209 -0
- package/lib/inventory/osPackageResolver.js +493 -0
- package/lib/inventory/osinfo.js +383 -0
- package/lib/inventory/osqueryTransform.js +274 -0
- package/lib/inventory/plugins.js +466 -0
- package/lib/inventory/protobom.js +231 -0
- package/lib/inventory/protobomLoader.js +43 -0
- package/lib/inventory/provenanceUtils.js +224 -0
- package/lib/inventory/purl.js +749 -0
- package/lib/inventory/rustFormulationParser.js +339 -0
- package/lib/inventory/sbomDocument.js +340 -0
- package/lib/inventory/source.js +1488 -0
- package/lib/inventory/spdx.js +361 -0
- package/lib/inventory/spdxExpression.js +512 -0
- package/lib/inventory/spdxUtils.js +107 -0
- package/lib/inventory/table.js +267 -0
- package/lib/inventory/traceRunner.js +439 -0
- package/lib/inventory/unicodeScan.js +147 -0
- package/lib/managers/binary.js +3459 -0
- package/lib/managers/containerutils.js +125 -0
- package/lib/managers/docker.js +2145 -0
- package/lib/managers/dockerConnection.js +162 -0
- package/lib/managers/oci.js +704 -0
- package/lib/managers/piptree.js +267 -0
- package/lib/parsers/cmakeCache.js +199 -0
- package/lib/parsers/gguf.js +492 -0
- package/lib/parsers/gitAiNotes.js +233 -0
- package/lib/parsers/gitmodules.js +239 -0
- package/lib/parsers/htmlExtract.js +610 -0
- package/lib/parsers/huggingfaceManifest.js +551 -0
- package/lib/parsers/huggingfaceUtils.js +506 -0
- package/lib/parsers/iri.js +618 -0
- package/lib/parsers/npmrc.js +99 -0
- package/lib/parsers/ollama.js +101 -0
- package/lib/parsers/xml.js +841 -0
- package/lib/server/openapi.yaml +433 -0
- package/lib/server/server.js +616 -0
- package/lib/stages/postgen/annotator.js +977 -0
- package/lib/stages/postgen/auditBom.js +468 -0
- package/lib/stages/postgen/postgen.js +1239 -0
- package/lib/stages/postgen/ruleEngine.js +731 -0
- package/lib/stages/postgen/sortBom.js +195 -0
- package/lib/stages/postgen/spdxConverter.js +796 -0
- package/lib/stages/postgen/specVersionCompat.js +703 -0
- package/lib/stages/pregen/envAudit.js +388 -0
- package/lib/stages/pregen/pregen.js +637 -0
- package/lib/third-party/README.md +9 -0
- package/lib/third-party/arborist/CHANGELOG.md +1109 -0
- package/lib/third-party/arborist/LICENSE.md +20 -0
- package/lib/third-party/arborist/README.md +315 -0
- package/lib/third-party/arborist/lib/arborist/index.js +258 -0
- package/lib/third-party/arborist/lib/arborist/load-actual.js +605 -0
- package/lib/third-party/arborist/lib/arborist/load-virtual.js +300 -0
- package/lib/third-party/arborist/lib/bin-links.js +120 -0
- package/lib/third-party/arborist/lib/calc-dep-flags.js +130 -0
- package/lib/third-party/arborist/lib/case-insensitive-map.js +51 -0
- package/lib/third-party/arborist/lib/consistent-resolve.js +42 -0
- package/lib/third-party/arborist/lib/debug.js +50 -0
- package/lib/third-party/arborist/lib/dep-valid.js +190 -0
- package/lib/third-party/arborist/lib/edge.js +417 -0
- package/lib/third-party/arborist/lib/from-path.js +36 -0
- package/lib/third-party/arborist/lib/gather-dep-set.js +43 -0
- package/lib/third-party/arborist/lib/index.js +22 -0
- package/lib/third-party/arborist/lib/inventory.js +138 -0
- package/lib/third-party/arborist/lib/link.js +169 -0
- package/lib/third-party/arborist/lib/node.js +1673 -0
- package/lib/third-party/arborist/lib/npm-extension.js +45 -0
- package/lib/third-party/arborist/lib/override-resolves.js +11 -0
- package/lib/third-party/arborist/lib/override-set.js +319 -0
- package/lib/third-party/arborist/lib/package-extensions.js +289 -0
- package/lib/third-party/arborist/lib/printable.js +210 -0
- package/lib/third-party/arborist/lib/proc-log.js +30 -0
- package/lib/third-party/arborist/lib/realpath.js +100 -0
- package/lib/third-party/arborist/lib/relpath.js +4 -0
- package/lib/third-party/arborist/lib/shrinkwrap.js +1291 -0
- package/lib/third-party/arborist/lib/spec-from-lock.js +34 -0
- package/lib/third-party/arborist/lib/tree-check.js +165 -0
- package/lib/third-party/arborist/lib/validate-npm-package-name.js +107 -0
- package/lib/third-party/arborist/lib/version-from-tgz.js +51 -0
- package/lib/third-party/arborist/lib/yarn-lock.js +397 -0
- package/lib/validator/bomValidator.js +985 -0
- package/lib/validator/complianceEngine.js +241 -0
- package/lib/validator/complianceRules.js +1680 -0
- package/lib/validator/generated/runtime.mjs +17 -0
- package/lib/validator/generated/validate-1.6.mjs +21258 -0
- package/lib/validator/generated/validate-1.7.mjs +24803 -0
- package/lib/validator/generated/validate-2.0.mjs +22931 -0
- package/lib/validator/index.js +246 -0
- package/lib/validator/reporters/annotations.js +142 -0
- package/lib/validator/reporters/console.js +160 -0
- package/lib/validator/reporters/index.js +41 -0
- package/lib/validator/reporters/json.js +37 -0
- package/lib/validator/reporters/sarif.js +184 -0
- package/package.json +209 -26
- package/types/bin/audit.d.ts +3 -0
- package/types/bin/audit.d.ts.map +1 -0
- package/types/bin/cdxgen.d.ts +3 -0
- package/types/bin/cdxgen.d.ts.map +1 -0
- package/types/bin/convert.d.ts +3 -0
- package/types/bin/convert.d.ts.map +1 -0
- package/types/bin/evinse.d.ts +3 -0
- package/types/bin/evinse.d.ts.map +1 -0
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts +3 -0
- package/types/bin/repl.d.ts.map +1 -0
- package/types/bin/sign.d.ts +3 -0
- package/types/bin/sign.d.ts.map +1 -0
- package/types/bin/tracebom.d.ts +3 -0
- package/types/bin/tracebom.d.ts.map +1 -0
- package/types/bin/validate.d.ts +14 -0
- package/types/bin/validate.d.ts.map +1 -0
- package/types/bin/verify.d.ts +3 -0
- package/types/bin/verify.d.ts.map +1 -0
- package/types/lib/audit/index.d.ts +153 -0
- package/types/lib/audit/index.d.ts.map +1 -0
- package/types/lib/audit/progress.d.ts +31 -0
- package/types/lib/audit/progress.d.ts.map +1 -0
- package/types/lib/audit/reporters.d.ts +62 -0
- package/types/lib/audit/reporters.d.ts.map +1 -0
- package/types/lib/audit/scoring.d.ts +36 -0
- package/types/lib/audit/scoring.d.ts.map +1 -0
- package/types/lib/audit/targets.d.ts +77 -0
- package/types/lib/audit/targets.d.ts.map +1 -0
- package/types/lib/cli/bomAssembly.d.ts +329 -0
- package/types/lib/cli/bomAssembly.d.ts.map +1 -0
- package/types/lib/cli/cliOptions.d.ts +156 -0
- package/types/lib/cli/cliOptions.d.ts.map +1 -0
- package/types/lib/cli/index.d.ts +107 -0
- package/types/lib/cli/index.d.ts.map +1 -0
- package/types/lib/cli/jsBom.d.ts +94 -0
- package/types/lib/cli/jsBom.d.ts.map +1 -0
- package/types/lib/cli/jvmBom.d.ts +54 -0
- package/types/lib/cli/jvmBom.d.ts.map +1 -0
- package/types/lib/cli/managedBom.d.ts +105 -0
- package/types/lib/cli/managedBom.d.ts.map +1 -0
- package/types/lib/cli/nativeBom.d.ts +143 -0
- package/types/lib/cli/nativeBom.d.ts.map +1 -0
- package/types/lib/core/activity.d.ts +178 -0
- package/types/lib/core/activity.d.ts.map +1 -0
- package/types/lib/core/env.d.ts +192 -0
- package/types/lib/core/env.d.ts.map +1 -0
- package/types/lib/core/fs.d.ts +158 -0
- package/types/lib/core/fs.d.ts.map +1 -0
- package/types/lib/core/httpClient.d.ts +149 -0
- package/types/lib/core/httpClient.d.ts.map +1 -0
- package/types/lib/core/logger.d.ts +50 -0
- package/types/lib/core/logger.d.ts.map +1 -0
- package/types/lib/core/parallel.d.ts +95 -0
- package/types/lib/core/parallel.d.ts.map +1 -0
- package/types/lib/core/paths.d.ts +36 -0
- package/types/lib/core/paths.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts +23 -0
- package/types/lib/core/projectConfig.d.ts.map +1 -0
- package/types/lib/core/propertySanitizer.d.ts +23 -0
- package/types/lib/core/propertySanitizer.d.ts.map +1 -0
- package/types/lib/core/spdx.d.ts +5 -0
- package/types/lib/core/spdx.d.ts.map +1 -0
- package/types/lib/core/state.d.ts +20 -0
- package/types/lib/core/state.d.ts.map +1 -0
- package/types/lib/core/text.d.ts +78 -0
- package/types/lib/core/text.d.ts.map +1 -0
- package/types/lib/core/ui.d.ts +87 -0
- package/types/lib/core/ui.d.ts.map +1 -0
- package/types/lib/core/urls.d.ts +43 -0
- package/types/lib/core/urls.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts +71 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -0
- package/types/lib/ecosystems/bunutils.d.ts +38 -0
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -0
- package/types/lib/ecosystems/caxa.d.ts +8 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -0
- package/types/lib/ecosystems/chromextutils.d.ts +97 -0
- package/types/lib/ecosystems/chromextutils.d.ts.map +1 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts +176 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +35 -0
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +76 -0
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -0
- package/types/lib/ecosystems/dotnetutils.d.ts +45 -0
- package/types/lib/ecosystems/dotnetutils.d.ts.map +1 -0
- package/types/lib/ecosystems/ecosystems.d.ts +279 -0
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -0
- package/types/lib/ecosystems/golem.d.ts +60 -0
- package/types/lib/ecosystems/golem.d.ts.map +1 -0
- package/types/lib/ecosystems/gradleutils.d.ts +139 -0
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -0
- package/types/lib/ecosystems/jsEvidence.d.ts +17 -0
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -0
- package/types/lib/ecosystems/npmutils.d.ts +183 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts +36 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts +116 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-gleam.d.ts +33 -0
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-go.d.ts +92 -0
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-js.d.ts +242 -0
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-jvm.d.ts +100 -0
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-misc.d.ts +450 -0
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-python.d.ts +145 -0
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rust.d.ts +56 -0
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-zig.d.ts +83 -0
- package/types/lib/ecosystems/parsers-zig.d.ts.map +1 -0
- package/types/lib/ecosystems/pep770.d.ts +38 -0
- package/types/lib/ecosystems/pep770.d.ts.map +1 -0
- package/types/lib/ecosystems/pylockutils.d.ts +68 -0
- package/types/lib/ecosystems/pylockutils.d.ts.map +1 -0
- package/types/lib/ecosystems/pythonutils.d.ts +70 -0
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -0
- package/types/lib/ecosystems/registryProvenance.d.ts +26 -0
- package/types/lib/ecosystems/registryProvenance.d.ts.map +1 -0
- package/types/lib/ecosystems/remote/huggingface.d.ts +31 -0
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -0
- package/types/lib/ecosystems/rubyutils.d.ts +182 -0
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -0
- package/types/lib/ecosystems/rusi.d.ts +40 -0
- package/types/lib/ecosystems/rusi.d.ts.map +1 -0
- package/types/lib/ecosystems/sbtutils.d.ts +179 -0
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -0
- package/types/lib/ecosystems/tea.d.ts +180 -0
- package/types/lib/ecosystems/tea.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +41 -0
- package/types/lib/ecosystems/utils.d.ts.map +1 -0
- package/types/lib/ecosystems/zigResolver.d.ts +70 -0
- package/types/lib/ecosystems/zigResolver.d.ts.map +1 -0
- package/types/lib/evinser/db.d.ts +17 -0
- package/types/lib/evinser/db.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +354 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -0
- package/types/lib/evinser/scalasem.d.ts +15 -0
- package/types/lib/evinser/scalasem.d.ts.map +1 -0
- package/types/lib/evinser/swiftsem.d.ts +103 -0
- package/types/lib/evinser/swiftsem.d.ts.map +1 -0
- package/types/lib/helpers/annotationFormatter.d.ts +23 -0
- package/types/lib/helpers/annotationFormatter.d.ts.map +1 -0
- package/types/lib/helpers/bomSigner.d.ts +28 -0
- package/types/lib/helpers/bomSigner.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts +52 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -0
- package/types/lib/helpers/remote/dependency-track.d.ts +23 -0
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
- package/types/lib/helpers/versutils.d.ts +8 -0
- package/types/lib/helpers/versutils.d.ts.map +1 -0
- package/types/lib/helpers/vsixutils.d.ts +130 -0
- package/types/lib/helpers/vsixutils.d.ts.map +1 -0
- package/types/lib/inventory/agentFormulationParser.d.ts +21 -0
- package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -0
- package/types/lib/inventory/aiCollector.d.ts +61 -0
- package/types/lib/inventory/aiCollector.d.ts.map +1 -0
- package/types/lib/inventory/aiInventory.d.ts +103 -0
- package/types/lib/inventory/aiInventory.d.ts.map +1 -0
- package/types/lib/inventory/aiModelVariants.d.ts +31 -0
- package/types/lib/inventory/aiModelVariants.d.ts.map +1 -0
- package/types/lib/inventory/aiOversightCollector.d.ts +28 -0
- package/types/lib/inventory/aiOversightCollector.d.ts.map +1 -0
- package/types/lib/inventory/aiProvenanceCollector.d.ts +13 -0
- package/types/lib/inventory/aiProvenanceCollector.d.ts.map +1 -0
- package/types/lib/inventory/analyzer.d.ts +157 -0
- package/types/lib/inventory/analyzer.d.ts.map +1 -0
- package/types/lib/inventory/analyzerScope.d.ts +106 -0
- package/types/lib/inventory/analyzerScope.d.ts.map +1 -0
- package/types/lib/inventory/astWorker.d.ts +9 -0
- package/types/lib/inventory/astWorker.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +159 -0
- package/types/lib/inventory/atomUtils.d.ts.map +1 -0
- package/types/lib/inventory/auditCategories.d.ts +80 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -0
- package/types/lib/inventory/bomUtils.d.ts +145 -0
- package/types/lib/inventory/bomUtils.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +28 -0
- package/types/lib/inventory/cacheCommands.d.ts.map +1 -0
- package/types/lib/inventory/cacheDir.d.ts +55 -0
- package/types/lib/inventory/cacheDir.d.ts.map +1 -0
- package/types/lib/inventory/cbomutils.d.ts +37 -0
- package/types/lib/inventory/cbomutils.d.ts.map +1 -0
- package/types/lib/inventory/cdxrs.d.ts +90 -0
- package/types/lib/inventory/cdxrs.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/azurePipelines.d.ts +27 -0
- package/types/lib/inventory/ciParsers/azurePipelines.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/circleCi.d.ts +27 -0
- package/types/lib/inventory/ciParsers/circleCi.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/common.d.ts +11 -0
- package/types/lib/inventory/ciParsers/common.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/githubActions.d.ts +38 -0
- package/types/lib/inventory/ciParsers/githubActions.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/gitlabCi.d.ts +26 -0
- package/types/lib/inventory/ciParsers/gitlabCi.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/jenkins.d.ts +26 -0
- package/types/lib/inventory/ciParsers/jenkins.d.ts.map +1 -0
- package/types/lib/inventory/citations.d.ts +90 -0
- package/types/lib/inventory/citations.d.ts.map +1 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts +14 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -0
- package/types/lib/inventory/containerRisk.d.ts +20 -0
- package/types/lib/inventory/containerRisk.d.ts.map +1 -0
- package/types/lib/inventory/cryptoAlgorithmFamily.d.ts +37 -0
- package/types/lib/inventory/cryptoAlgorithmFamily.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +140 -0
- package/types/lib/inventory/deps.d.ts.map +1 -0
- package/types/lib/inventory/depsUtils.d.ts +74 -0
- package/types/lib/inventory/depsUtils.d.ts.map +1 -0
- package/types/lib/inventory/display.d.ts +227 -0
- package/types/lib/inventory/display.d.ts.map +1 -0
- package/types/lib/inventory/dosai.d.ts +130 -0
- package/types/lib/inventory/dosai.d.ts.map +1 -0
- package/types/lib/inventory/dosaiParsers.d.ts +59 -0
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -0
- package/types/lib/inventory/dynamic.d.ts +25 -0
- package/types/lib/inventory/dynamic.d.ts.map +1 -0
- package/types/lib/inventory/envcontext.d.ts +377 -0
- package/types/lib/inventory/envcontext.d.ts.map +1 -0
- package/types/lib/inventory/evidenceUtils.d.ts +74 -0
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -0
- package/types/lib/inventory/fetchBatch.d.ts +127 -0
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -0
- package/types/lib/inventory/fetchRate.d.ts +118 -0
- package/types/lib/inventory/fetchRate.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts +31 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -0
- package/types/lib/inventory/formulationParsers.d.ts +50 -0
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -0
- package/types/lib/inventory/gtfobins.d.ts +27 -0
- package/types/lib/inventory/gtfobins.d.ts.map +1 -0
- package/types/lib/inventory/hbom.d.ts +58 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -0
- package/types/lib/inventory/hbomAnalysis.d.ts +56 -0
- package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/inventory/hbomLoader.d.ts +7 -0
- package/types/lib/inventory/hbomLoader.d.ts.map +1 -0
- package/types/lib/inventory/hostTopology.d.ts +47 -0
- package/types/lib/inventory/hostTopology.d.ts.map +1 -0
- package/types/lib/inventory/inventoryStats.d.ts +42 -0
- package/types/lib/inventory/inventoryStats.d.ts.map +1 -0
- package/types/lib/inventory/jsonLike.d.ts +23 -0
- package/types/lib/inventory/jsonLike.d.ts.map +1 -0
- package/types/lib/inventory/licenseEnhancer.d.ts +70 -0
- package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -0
- package/types/lib/inventory/lolbas.d.ts +16 -0
- package/types/lib/inventory/lolbas.d.ts.map +1 -0
- package/types/lib/inventory/mcp.d.ts +29 -0
- package/types/lib/inventory/mcp.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts +20 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -0
- package/types/lib/inventory/mcpDiscovery.d.ts +33 -0
- package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -0
- package/types/lib/inventory/mcpPinning.d.ts +11 -0
- package/types/lib/inventory/mcpPinning.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +49 -0
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -0
- package/types/lib/inventory/osinfo.d.ts +201 -0
- package/types/lib/inventory/osinfo.d.ts.map +1 -0
- package/types/lib/inventory/osqueryTransform.d.ts +84 -0
- package/types/lib/inventory/osqueryTransform.d.ts.map +1 -0
- package/types/lib/inventory/plugins.d.ts +58 -0
- package/types/lib/inventory/plugins.d.ts.map +1 -0
- package/types/lib/inventory/protobom.d.ts +71 -0
- package/types/lib/inventory/protobom.d.ts.map +1 -0
- package/types/lib/inventory/protobomLoader.d.ts +17 -0
- package/types/lib/inventory/protobomLoader.d.ts.map +1 -0
- package/types/lib/inventory/provenanceUtils.d.ts +98 -0
- package/types/lib/inventory/provenanceUtils.d.ts.map +1 -0
- package/types/lib/inventory/purl.d.ts +313 -0
- package/types/lib/inventory/purl.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts +17 -0
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -0
- package/types/lib/inventory/sbomDocument.d.ts +59 -0
- package/types/lib/inventory/sbomDocument.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +163 -0
- package/types/lib/inventory/source.d.ts.map +1 -0
- package/types/lib/inventory/spdx.d.ts +66 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -0
- package/types/lib/inventory/spdxExpression.d.ts +58 -0
- package/types/lib/inventory/spdxExpression.d.ts.map +1 -0
- package/types/lib/inventory/spdxUtils.d.ts +12 -0
- package/types/lib/inventory/spdxUtils.d.ts.map +1 -0
- package/types/lib/inventory/table.d.ts +22 -0
- package/types/lib/inventory/table.d.ts.map +1 -0
- package/types/lib/inventory/traceRunner.d.ts +80 -0
- package/types/lib/inventory/traceRunner.d.ts.map +1 -0
- package/types/lib/inventory/unicodeScan.d.ts +46 -0
- package/types/lib/inventory/unicodeScan.d.ts.map +1 -0
- package/types/lib/managers/binary.d.ts +147 -0
- package/types/lib/managers/binary.d.ts.map +1 -0
- package/types/lib/managers/containerutils.d.ts +30 -0
- package/types/lib/managers/containerutils.d.ts.map +1 -0
- package/types/lib/managers/docker.d.ts +157 -0
- package/types/lib/managers/docker.d.ts.map +1 -0
- package/types/lib/managers/dockerConnection.d.ts +42 -0
- package/types/lib/managers/dockerConnection.d.ts.map +1 -0
- package/types/lib/managers/oci.d.ts +21 -0
- package/types/lib/managers/oci.d.ts.map +1 -0
- package/types/lib/managers/piptree.d.ts +13 -0
- package/types/lib/managers/piptree.d.ts.map +1 -0
- package/types/lib/parsers/cmakeCache.d.ts +70 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -0
- package/types/lib/parsers/gguf.d.ts +39 -0
- package/types/lib/parsers/gguf.d.ts.map +1 -0
- package/types/lib/parsers/gitAiNotes.d.ts +15 -0
- package/types/lib/parsers/gitAiNotes.d.ts.map +1 -0
- package/types/lib/parsers/gitmodules.d.ts +88 -0
- package/types/lib/parsers/gitmodules.d.ts.map +1 -0
- package/types/lib/parsers/htmlExtract.d.ts +34 -0
- package/types/lib/parsers/htmlExtract.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceManifest.d.ts +153 -0
- package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts +155 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -0
- package/types/lib/parsers/iri.d.ts +68 -0
- package/types/lib/parsers/iri.d.ts.map +1 -0
- package/types/lib/parsers/npmrc.d.ts +33 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -0
- package/types/lib/parsers/ollama.d.ts +22 -0
- package/types/lib/parsers/ollama.d.ts.map +1 -0
- package/types/lib/parsers/xml.d.ts +47 -0
- package/types/lib/parsers/xml.d.ts.map +1 -0
- package/types/lib/server/server.d.ts +51 -0
- package/types/lib/server/server.d.ts.map +1 -0
- package/types/lib/stages/postgen/annotator.d.ts +36 -0
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -0
- package/types/lib/stages/postgen/auditBom.d.ts +92 -0
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/postgen.d.ts +59 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
- package/types/lib/stages/postgen/sortBom.d.ts +34 -0
- package/types/lib/stages/postgen/sortBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts +11 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts.map +1 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts +71 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -0
- package/types/lib/stages/pregen/envAudit.d.ts +14 -0
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
- package/types/lib/stages/pregen/pregen.d.ts +59 -0
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts +47 -0
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts +4 -0
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts +4 -0
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/bin-links.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/bin-links.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts +9 -0
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/debug.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/debug.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/dep-valid.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/dep-valid.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/edge.d.ts +46 -0
- package/types/lib/third-party/arborist/lib/edge.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/from-path.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/from-path.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/index.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/index.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/inventory.d.ts +14 -0
- package/types/lib/third-party/arborist/lib/inventory.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/link.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/link.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/node.d.ts +112 -0
- package/types/lib/third-party/arborist/lib/node.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/npm-extension.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/npm-extension.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/override-resolves.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/override-resolves.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/override-set.d.ts +27 -0
- package/types/lib/third-party/arborist/lib/override-set.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/package-extensions.d.ts +36 -0
- package/types/lib/third-party/arborist/lib/package-extensions.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/printable.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/printable.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/proc-log.d.ts +20 -0
- package/types/lib/third-party/arborist/lib/proc-log.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/realpath.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/realpath.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/relpath.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/relpath.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts +54 -0
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/tree-check.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/tree-check.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts +13 -0
- package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts +6 -0
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts +35 -0
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts.map +1 -0
- package/types/lib/validator/bomValidator.d.ts +40 -0
- package/types/lib/validator/bomValidator.d.ts.map +1 -0
- package/types/lib/validator/complianceEngine.d.ts +72 -0
- package/types/lib/validator/complianceEngine.d.ts.map +1 -0
- package/types/lib/validator/complianceRules.d.ts +61 -0
- package/types/lib/validator/complianceRules.d.ts.map +1 -0
- package/types/lib/validator/index.d.ts +101 -0
- package/types/lib/validator/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/annotations.d.ts +37 -0
- package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
- package/types/lib/validator/reporters/console.d.ts +34 -0
- package/types/lib/validator/reporters/console.d.ts.map +1 -0
- package/types/lib/validator/reporters/index.d.ts +30 -0
- package/types/lib/validator/reporters/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/json.d.ts +11 -0
- package/types/lib/validator/reporters/json.d.ts.map +1 -0
- package/types/lib/validator/reporters/sarif.d.ts +22 -0
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
- package/mod.d.ts +0 -7
- package/mod.js +0 -22
|
@@ -0,0 +1,1793 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { arch, homedir } from "node:os";
|
|
3
|
+
import { basename, delimiter, dirname, join } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
|
|
6
|
+
import { compareLoose } from "semver";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
DEBUG_MODE,
|
|
10
|
+
isSecureMode,
|
|
11
|
+
readEnvironmentVariable,
|
|
12
|
+
} from "../core/activity.js";
|
|
13
|
+
import {
|
|
14
|
+
CARGO_CMD,
|
|
15
|
+
DOTNET_CMD,
|
|
16
|
+
GCC_CMD,
|
|
17
|
+
GO_CMD,
|
|
18
|
+
getJavaCommand,
|
|
19
|
+
getPythonCommand,
|
|
20
|
+
isBun,
|
|
21
|
+
isDeno,
|
|
22
|
+
isNode,
|
|
23
|
+
NPM_CMD,
|
|
24
|
+
RUBY_CMD,
|
|
25
|
+
RUSTC_CMD,
|
|
26
|
+
SWIFT_CMD,
|
|
27
|
+
} from "../core/env.js";
|
|
28
|
+
import {
|
|
29
|
+
getTmpDir,
|
|
30
|
+
MAX_BUFFER,
|
|
31
|
+
safeExistsSync,
|
|
32
|
+
safeSpawnSync,
|
|
33
|
+
} from "../core/fs.js";
|
|
34
|
+
import { diagnosticStream } from "../core/logger.js";
|
|
35
|
+
import { dirNameStr, isMac, isWin } from "../core/paths.js";
|
|
36
|
+
import { applyPurl, tryBuildPurl } from "./purl.js";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Git executable name used for all git invocations, overridable via GIT_CMD.
|
|
40
|
+
*
|
|
41
|
+
* @type {string}
|
|
42
|
+
*/
|
|
43
|
+
export const GIT_COMMAND = readEnvironmentVariable("GIT_CMD") || "git";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Config overrides applied (via `-c`) to every git invocation to neutralize
|
|
47
|
+
* repository-controlled code-execution vectors. A cloned/untrusted repo can set
|
|
48
|
+
* these in its local `.git/config`, so we force-disable them:
|
|
49
|
+
* - `core.fsmonitor=false` — a repo-set fsmonitor value is a command git runs.
|
|
50
|
+
* - `core.hooksPath=/dev/null` — prevents any hook script from executing.
|
|
51
|
+
* - `safe.bareRepository=explicit` — avoids operating on an embedded bare repo.
|
|
52
|
+
* `-c` overrides take precedence over the repo-local config. Diff-producing
|
|
53
|
+
* commands (`git show`/`git diff`) additionally pass `--no-ext-diff`/
|
|
54
|
+
* `--no-textconv` to block `.gitattributes`-driven external diff and textconv
|
|
55
|
+
* drivers, which are executed as shell commands.
|
|
56
|
+
*/
|
|
57
|
+
const GIT_HARDENING_CONFIG_ARGS = Object.freeze([
|
|
58
|
+
"-c",
|
|
59
|
+
"core.fsmonitor=false",
|
|
60
|
+
"-c",
|
|
61
|
+
"core.hooksPath=/dev/null",
|
|
62
|
+
"-c",
|
|
63
|
+
"safe.bareRepository=explicit",
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Environment applied to every git invocation. Disables interactive prompts and,
|
|
68
|
+
* in secure mode, ignores system/global git config so only the hardened `-c`
|
|
69
|
+
* overrides and the (untrusted) repo config remain, mirroring hardenedGitCommand.
|
|
70
|
+
*
|
|
71
|
+
* @returns {Object} environment for spawning git
|
|
72
|
+
*/
|
|
73
|
+
function hardenedGitEnv() {
|
|
74
|
+
const env = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
|
|
75
|
+
if (isSecureMode) {
|
|
76
|
+
env.GIT_CONFIG_NOSYSTEM = "1";
|
|
77
|
+
env.GIT_CONFIG_GLOBAL = "/dev/null";
|
|
78
|
+
}
|
|
79
|
+
return env;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* sdkman tool aliases mapping java version identifiers to candidate ids.
|
|
84
|
+
*
|
|
85
|
+
* Each alias can be overridden via the matching `JAVA*_TOOL` environment
|
|
86
|
+
* variable and otherwise defaults to a Temurin candidate version.
|
|
87
|
+
*
|
|
88
|
+
* @type {Object<string, string>}
|
|
89
|
+
*/
|
|
90
|
+
export const SDKMAN_JAVA_TOOL_ALIASES = {
|
|
91
|
+
java8: readEnvironmentVariable("JAVA8_TOOL") || "8.0.452-amzn", // Temurin no longer offers java8 :(
|
|
92
|
+
java11: readEnvironmentVariable("JAVA11_TOOL") || "11.0.31-tem",
|
|
93
|
+
java17: readEnvironmentVariable("JAVA17_TOOL") || "17.0.19-tem",
|
|
94
|
+
java21: readEnvironmentVariable("JAVA21_TOOL") || "21.0.11-tem",
|
|
95
|
+
java22: readEnvironmentVariable("JAVA22_TOOL") || "22.0.2-tem",
|
|
96
|
+
java23: readEnvironmentVariable("JAVA23_TOOL") || "23.0.2-tem",
|
|
97
|
+
java24: readEnvironmentVariable("JAVA24_TOOL") || "24.0.2-tem",
|
|
98
|
+
java25: readEnvironmentVariable("JAVA25_TOOL") || "25.0.3-tem",
|
|
99
|
+
java26: readEnvironmentVariable("JAVA26_TOOL") || "26.0.1-tem",
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Retrieves a git config item
|
|
104
|
+
* @param {string} configKey Git config key
|
|
105
|
+
* @param {string} dir repo directory
|
|
106
|
+
*
|
|
107
|
+
* @returns Output from git config or undefined
|
|
108
|
+
*/
|
|
109
|
+
export function getGitConfig(configKey, dir) {
|
|
110
|
+
return execGitCommand(dir, ["config", "--get", configKey]);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Retrieves the git origin url
|
|
115
|
+
* @param {string} dir repo directory
|
|
116
|
+
*
|
|
117
|
+
* @returns Output from git config or undefined
|
|
118
|
+
*/
|
|
119
|
+
export function getOriginUrl(dir) {
|
|
120
|
+
return getGitConfig("remote.origin.url", dir);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Retrieves the git branch name
|
|
125
|
+
* @param {string} configKey Git config key
|
|
126
|
+
* @param {string} dir repo directory
|
|
127
|
+
*
|
|
128
|
+
* @returns Output from git config or undefined
|
|
129
|
+
*/
|
|
130
|
+
export function getBranch(_configKey, dir) {
|
|
131
|
+
return execGitCommand(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Retrieves the tree and parent hash for a git repo
|
|
136
|
+
* @param {string} dir repo directory
|
|
137
|
+
*
|
|
138
|
+
* @returns Output from git cat-file or undefined
|
|
139
|
+
*/
|
|
140
|
+
export function gitTreeHashes(dir) {
|
|
141
|
+
const treeHashes = {};
|
|
142
|
+
const output = execGitCommand(dir, ["cat-file", "commit", "HEAD"]);
|
|
143
|
+
if (output) {
|
|
144
|
+
output.split("\n").forEach((l) => {
|
|
145
|
+
l = l.replaceAll("\r", "");
|
|
146
|
+
if (l === "\n" || l.startsWith("#")) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (l.startsWith("tree") || l.startsWith("parent")) {
|
|
150
|
+
const tmpA = l.split(" ");
|
|
151
|
+
if (tmpA && tmpA.length === 2) {
|
|
152
|
+
treeHashes[tmpA[0]] = tmpA[1];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return treeHashes;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Retrieves the files list from git
|
|
162
|
+
* @param {string} dir repo directory
|
|
163
|
+
*
|
|
164
|
+
* @returns Output from git config or undefined
|
|
165
|
+
*/
|
|
166
|
+
export function listFiles(dir) {
|
|
167
|
+
const filesList = [];
|
|
168
|
+
const output = execGitCommand(dir, [
|
|
169
|
+
"ls-tree",
|
|
170
|
+
"-l",
|
|
171
|
+
"-r",
|
|
172
|
+
"--full-tree",
|
|
173
|
+
"HEAD",
|
|
174
|
+
]);
|
|
175
|
+
if (output) {
|
|
176
|
+
output.split("\n").forEach((l) => {
|
|
177
|
+
l = l.replaceAll("\r", "");
|
|
178
|
+
if (l === "\n" || l.startsWith("#")) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const tmpA = l.split(" ");
|
|
182
|
+
if (tmpA && tmpA.length >= 5) {
|
|
183
|
+
const lastParts = tmpA[tmpA.length - 1].split("\t");
|
|
184
|
+
filesList.push({
|
|
185
|
+
hash: tmpA[2],
|
|
186
|
+
name: lastParts[lastParts.length - 1],
|
|
187
|
+
omniborId: `gitoid:blob:sha1:${tmpA[2]}`,
|
|
188
|
+
swhid: `swh:1:rev:${tmpA[2]}`,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return filesList;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Execute a git command
|
|
198
|
+
*
|
|
199
|
+
* @param {string} dir Repo directory
|
|
200
|
+
* @param {Array} args arguments to git command
|
|
201
|
+
*
|
|
202
|
+
* @returns Output from the git command
|
|
203
|
+
*/
|
|
204
|
+
export function execGitCommand(dir, args) {
|
|
205
|
+
// Prepend hardening `-c` overrides before the subcommand and run git with a
|
|
206
|
+
// hardened environment so a scanned/untrusted repo cannot execute hooks,
|
|
207
|
+
// fsmonitor commands, or config-driven scripts.
|
|
208
|
+
return getCommandOutput(
|
|
209
|
+
GIT_COMMAND,
|
|
210
|
+
dir,
|
|
211
|
+
[...GIT_HARDENING_CONFIG_ARGS, ...args],
|
|
212
|
+
{
|
|
213
|
+
env: hardenedGitEnv(),
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Retrieves the author names and emails from the git commit log
|
|
220
|
+
*
|
|
221
|
+
* @param {string} dir Repo directory
|
|
222
|
+
* @param {number} maxCount Maximum number of commits to retrieve
|
|
223
|
+
*
|
|
224
|
+
* @returns {Array<{name: string, email: string}>} Array of authors
|
|
225
|
+
*/
|
|
226
|
+
export function gitLogAuthors(dir, maxCount = 20) {
|
|
227
|
+
const count = safeGitLogCount(maxCount);
|
|
228
|
+
const output = execGitCommand(dir, [
|
|
229
|
+
"log",
|
|
230
|
+
"-n",
|
|
231
|
+
`${count}`,
|
|
232
|
+
"--format=%an|%ae",
|
|
233
|
+
]);
|
|
234
|
+
if (!output) {
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
const authors = [];
|
|
238
|
+
const lines = output.split("\n");
|
|
239
|
+
const seen = new Set();
|
|
240
|
+
for (const line of lines) {
|
|
241
|
+
const trimmed = line.trim();
|
|
242
|
+
if (!trimmed) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (seen.has(trimmed)) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
seen.add(trimmed);
|
|
249
|
+
const parts = trimmed.split("|");
|
|
250
|
+
const name = parts[0]?.trim() || "";
|
|
251
|
+
const email = parts[1]?.trim() || "";
|
|
252
|
+
authors.push({ name, email });
|
|
253
|
+
}
|
|
254
|
+
return authors;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Retrieves the commit logs for a git repo, returning hashes and messages
|
|
259
|
+
*
|
|
260
|
+
* @param {string} dir Repo directory
|
|
261
|
+
* @param {number} maxCount Maximum number of commits to retrieve
|
|
262
|
+
*
|
|
263
|
+
* @returns {Array<{hash: string, message: string}>} Array of commit objects
|
|
264
|
+
*/
|
|
265
|
+
export function gitLogTrailers(dir, maxCount = 20) {
|
|
266
|
+
const count = safeGitLogCount(maxCount);
|
|
267
|
+
// %x1e (record separator) is a control character that cannot appear in a
|
|
268
|
+
// commit message, so it is a safe boundary between commits.
|
|
269
|
+
const output = execGitCommand(dir, [
|
|
270
|
+
"log",
|
|
271
|
+
"-n",
|
|
272
|
+
`${count}`,
|
|
273
|
+
"--format=%H%n%B%x1e",
|
|
274
|
+
]);
|
|
275
|
+
if (!output) {
|
|
276
|
+
return [];
|
|
277
|
+
}
|
|
278
|
+
const commits = [];
|
|
279
|
+
const parts = output.split("\x1e");
|
|
280
|
+
for (const part of parts) {
|
|
281
|
+
const trimmed = part.trim();
|
|
282
|
+
if (!trimmed) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const lines = trimmed.split("\n");
|
|
286
|
+
const hash = lines[0]?.trim();
|
|
287
|
+
const message = lines.slice(1).join("\n").trim();
|
|
288
|
+
if (hash) {
|
|
289
|
+
commits.push({ hash, message });
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return commits;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Collect Java version and installed modules
|
|
297
|
+
*
|
|
298
|
+
* @param {string} dir Working directory
|
|
299
|
+
* @returns Object containing the java details
|
|
300
|
+
*/
|
|
301
|
+
export function collectJavaInfo(dir) {
|
|
302
|
+
const versionDesc = getCommandOutput(getJavaCommand(), dir, ["--version"]);
|
|
303
|
+
const moduleDesc =
|
|
304
|
+
getCommandOutput(getJavaCommand(), dir, ["--list-modules"]) || "";
|
|
305
|
+
if (versionDesc) {
|
|
306
|
+
return {
|
|
307
|
+
type: "platform",
|
|
308
|
+
name: "java",
|
|
309
|
+
version: versionDesc.split("\n")[0].replace("java ", ""),
|
|
310
|
+
description: versionDesc,
|
|
311
|
+
properties: [
|
|
312
|
+
{
|
|
313
|
+
name: "java:modules",
|
|
314
|
+
value: moduleDesc.replaceAll("\n", ", "),
|
|
315
|
+
},
|
|
316
|
+
],
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Collect dotnet version
|
|
324
|
+
*
|
|
325
|
+
* @param {string} dir Working directory
|
|
326
|
+
* @returns Object containing dotnet details
|
|
327
|
+
*/
|
|
328
|
+
export function collectDotnetInfo(dir) {
|
|
329
|
+
const versionDesc = getCommandOutput(DOTNET_CMD, dir, ["--version"]);
|
|
330
|
+
const moduleDesc =
|
|
331
|
+
getCommandOutput(DOTNET_CMD, dir, ["--list-runtimes"]) || "";
|
|
332
|
+
if (versionDesc) {
|
|
333
|
+
return {
|
|
334
|
+
type: "platform",
|
|
335
|
+
name: "dotnet",
|
|
336
|
+
version: versionDesc.trim(),
|
|
337
|
+
description: moduleDesc.replaceAll("\n", "\\n"),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Collect python version
|
|
345
|
+
*
|
|
346
|
+
* @param {string} dir Working directory
|
|
347
|
+
* @returns Object containing python details
|
|
348
|
+
*/
|
|
349
|
+
export function collectPythonInfo(dir) {
|
|
350
|
+
const versionDesc = getCommandOutput(getPythonCommand(), dir, [
|
|
351
|
+
"-S",
|
|
352
|
+
"--version",
|
|
353
|
+
]);
|
|
354
|
+
const moduleDesc =
|
|
355
|
+
getCommandOutput(getPythonCommand(), dir, [
|
|
356
|
+
"-I",
|
|
357
|
+
"-m",
|
|
358
|
+
"pip",
|
|
359
|
+
"--version",
|
|
360
|
+
]) || "";
|
|
361
|
+
if (versionDesc) {
|
|
362
|
+
return {
|
|
363
|
+
type: "platform",
|
|
364
|
+
name: "python",
|
|
365
|
+
version: versionDesc.replace("Python ", ""),
|
|
366
|
+
description: moduleDesc.replaceAll("\n", "\\n"),
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Collect node runtime version
|
|
374
|
+
*
|
|
375
|
+
* @param {string} dir Working directory
|
|
376
|
+
* @returns {Object} Object containing node details
|
|
377
|
+
*/
|
|
378
|
+
export function collectNodeInfo(dir) {
|
|
379
|
+
const runtimeInfo = getRuntimeInformation();
|
|
380
|
+
const nodeInfo = {
|
|
381
|
+
type: "platform",
|
|
382
|
+
name: runtimeInfo.runtime,
|
|
383
|
+
version: runtimeInfo.version,
|
|
384
|
+
components: runtimeInfo.components,
|
|
385
|
+
};
|
|
386
|
+
const moduleDesc = getCommandOutput(NPM_CMD, dir, ["--version"]);
|
|
387
|
+
if (moduleDesc) {
|
|
388
|
+
nodeInfo.description = `npm: ${moduleDesc}`;
|
|
389
|
+
}
|
|
390
|
+
return nodeInfo;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Collect gcc version
|
|
395
|
+
*
|
|
396
|
+
* @param {string} dir Working directory
|
|
397
|
+
* @returns Object containing gcc details
|
|
398
|
+
*/
|
|
399
|
+
export function collectGccInfo(dir) {
|
|
400
|
+
const versionDesc = getCommandOutput(GCC_CMD, dir, ["--version"]);
|
|
401
|
+
const moduleDesc = getCommandOutput(GCC_CMD, dir, ["-print-search-dirs"]);
|
|
402
|
+
if (versionDesc) {
|
|
403
|
+
return {
|
|
404
|
+
type: "platform",
|
|
405
|
+
name: "gcc",
|
|
406
|
+
version: versionDesc.split("\n")[0],
|
|
407
|
+
description: (moduleDesc || "").replaceAll("\n", "\\n"),
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
return undefined;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Collect rust version
|
|
415
|
+
*
|
|
416
|
+
* @param {string} dir Working directory
|
|
417
|
+
* @returns Object containing rust details
|
|
418
|
+
*/
|
|
419
|
+
export function collectRustInfo(dir) {
|
|
420
|
+
const versionDesc = getCommandOutput(RUSTC_CMD, dir, ["--version"]);
|
|
421
|
+
const moduleDesc = getCommandOutput(CARGO_CMD, dir, ["--version"]);
|
|
422
|
+
if (versionDesc) {
|
|
423
|
+
return {
|
|
424
|
+
type: "platform",
|
|
425
|
+
name: "rustc",
|
|
426
|
+
version: versionDesc.trim(),
|
|
427
|
+
description: (moduleDesc || "").trim(),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
return undefined;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Collect go version
|
|
435
|
+
*
|
|
436
|
+
* @param {string} dir Working directory
|
|
437
|
+
* @returns Object containing go details
|
|
438
|
+
*/
|
|
439
|
+
export function collectGoInfo(dir) {
|
|
440
|
+
const versionDesc = getCommandOutput(GO_CMD, dir, ["version"]);
|
|
441
|
+
if (versionDesc) {
|
|
442
|
+
return {
|
|
443
|
+
type: "platform",
|
|
444
|
+
name: "go",
|
|
445
|
+
version: versionDesc.trim(),
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
return undefined;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Collect swift version
|
|
453
|
+
*
|
|
454
|
+
* @param {string} dir Working directory
|
|
455
|
+
* @returns Object containing swift details
|
|
456
|
+
*/
|
|
457
|
+
export function collectSwiftInfo(dir) {
|
|
458
|
+
const versionDesc = getCommandOutput(SWIFT_CMD, dir, ["--version"]);
|
|
459
|
+
if (versionDesc) {
|
|
460
|
+
return {
|
|
461
|
+
type: "platform",
|
|
462
|
+
name: "swift",
|
|
463
|
+
version: versionDesc.trim(),
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
return undefined;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Collect Ruby version
|
|
471
|
+
*
|
|
472
|
+
* @param {string} dir Working directory
|
|
473
|
+
* @returns Object containing Ruby details
|
|
474
|
+
*/
|
|
475
|
+
export function collectRubyInfo(dir) {
|
|
476
|
+
const versionDesc = getCommandOutput(RUBY_CMD, dir, ["--version"]);
|
|
477
|
+
if (versionDesc) {
|
|
478
|
+
return {
|
|
479
|
+
type: "platform",
|
|
480
|
+
name: "ruby",
|
|
481
|
+
version: versionDesc.trim(),
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
return undefined;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Method to run a swift command
|
|
489
|
+
*
|
|
490
|
+
* @param {String} dir Working directory
|
|
491
|
+
* @param {Array} args Command arguments
|
|
492
|
+
* @returns Object containing swift details
|
|
493
|
+
*/
|
|
494
|
+
export function runSwiftCommand(dir, args) {
|
|
495
|
+
return getCommandOutput(SWIFT_CMD, dir, args);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Collect toolchain information components for the current environment.
|
|
500
|
+
*
|
|
501
|
+
* Probes the working directory for java, dotnet, python, node, gcc, rust, go,
|
|
502
|
+
* and ruby toolchains and returns one component per detected tool.
|
|
503
|
+
*
|
|
504
|
+
* @param {string} dir Working directory to inspect
|
|
505
|
+
* @returns {Object[]} Array of toolchain component objects; empty when nothing is detected
|
|
506
|
+
*/
|
|
507
|
+
export function collectEnvInfo(dir) {
|
|
508
|
+
const infoComponents = [];
|
|
509
|
+
let cmp = collectJavaInfo(dir);
|
|
510
|
+
if (cmp) {
|
|
511
|
+
infoComponents.push(cmp);
|
|
512
|
+
}
|
|
513
|
+
cmp = collectDotnetInfo(dir);
|
|
514
|
+
if (cmp) {
|
|
515
|
+
infoComponents.push(cmp);
|
|
516
|
+
}
|
|
517
|
+
cmp = collectPythonInfo(dir);
|
|
518
|
+
if (cmp) {
|
|
519
|
+
infoComponents.push(cmp);
|
|
520
|
+
}
|
|
521
|
+
cmp = collectNodeInfo(dir);
|
|
522
|
+
if (cmp) {
|
|
523
|
+
infoComponents.push(cmp);
|
|
524
|
+
}
|
|
525
|
+
cmp = collectGccInfo(dir);
|
|
526
|
+
if (cmp) {
|
|
527
|
+
infoComponents.push(cmp);
|
|
528
|
+
}
|
|
529
|
+
cmp = collectRustInfo(dir);
|
|
530
|
+
if (cmp) {
|
|
531
|
+
infoComponents.push(cmp);
|
|
532
|
+
}
|
|
533
|
+
cmp = collectGoInfo(dir);
|
|
534
|
+
if (cmp) {
|
|
535
|
+
infoComponents.push(cmp);
|
|
536
|
+
}
|
|
537
|
+
cmp = collectRubyInfo(dir);
|
|
538
|
+
if (cmp) {
|
|
539
|
+
infoComponents.push(cmp);
|
|
540
|
+
}
|
|
541
|
+
return infoComponents;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Execute any command to retrieve the output
|
|
546
|
+
*
|
|
547
|
+
* @param {*} cmd Command to execute
|
|
548
|
+
* @param {*} dir working directory
|
|
549
|
+
* @param {*} args arguments
|
|
550
|
+
* @param {Object} [spawnOverrides] extra options merged into spawnSync (e.g. env)
|
|
551
|
+
* @returns String output from the command or undefined in case of error
|
|
552
|
+
*/
|
|
553
|
+
const getCommandOutput = (cmd, dir, args, spawnOverrides = {}) => {
|
|
554
|
+
let commandToUse = cmd;
|
|
555
|
+
// If the command includes space, automatically move it to the front of the args.
|
|
556
|
+
if (cmd?.trim().includes(" ")) {
|
|
557
|
+
const tmpA = cmd.split(" ");
|
|
558
|
+
commandToUse = tmpA.shift();
|
|
559
|
+
if (args?.length && tmpA.length) {
|
|
560
|
+
args = tmpA.concat(args);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (DEBUG_MODE) {
|
|
564
|
+
if (dir) {
|
|
565
|
+
if (safeExistsSync(join(dir, commandToUse))) {
|
|
566
|
+
console.warn(
|
|
567
|
+
`SECURE MODE: Found ${commandToUse} inside ${dir}. This command will not be executed.`,
|
|
568
|
+
);
|
|
569
|
+
return undefined;
|
|
570
|
+
}
|
|
571
|
+
console.log(`Executing ${commandToUse} in ${dir}`);
|
|
572
|
+
} else {
|
|
573
|
+
console.log(`Executing ${commandToUse}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
const result = safeSpawnSync(commandToUse, args, {
|
|
577
|
+
cwd: dir,
|
|
578
|
+
shell: isWin,
|
|
579
|
+
maxBuffer: MAX_BUFFER * 2,
|
|
580
|
+
...spawnOverrides,
|
|
581
|
+
});
|
|
582
|
+
const stdout = result.stdout ? result.stdout.toString() : "";
|
|
583
|
+
const stderr = result.stderr ? result.stderr.toString() : "";
|
|
584
|
+
return `${stdout}\n${stderr}`.trim() || undefined;
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Method to check if sdkman is available.
|
|
589
|
+
*/
|
|
590
|
+
export function isSdkmanAvailable() {
|
|
591
|
+
let isSdkmanSetup =
|
|
592
|
+
["SDKMAN_DIR", "SDKMAN_CANDIDATES_DIR"].filter(
|
|
593
|
+
(v) =>
|
|
594
|
+
readEnvironmentVariable(v) &&
|
|
595
|
+
safeExistsSync(readEnvironmentVariable(v)),
|
|
596
|
+
).length >= 1;
|
|
597
|
+
if (!isSdkmanSetup && safeExistsSync(join(homedir(), ".sdkman", "bin"))) {
|
|
598
|
+
process.env.SDKMAN_DIR = join(homedir(), ".sdkman");
|
|
599
|
+
process.env.SDKMAN_CANDIDATES_DIR = join(
|
|
600
|
+
homedir(),
|
|
601
|
+
".sdkman",
|
|
602
|
+
"candidates",
|
|
603
|
+
);
|
|
604
|
+
isSdkmanSetup = true;
|
|
605
|
+
}
|
|
606
|
+
return isSdkmanSetup;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Method to check if nvm is available.
|
|
611
|
+
*/
|
|
612
|
+
export function isNvmAvailable() {
|
|
613
|
+
const result = safeSpawnSync(readEnvironmentVariable("SHELL") || "bash", [
|
|
614
|
+
"-i",
|
|
615
|
+
"-c",
|
|
616
|
+
readEnvironmentVariable("NVM_CMD") || "nvm",
|
|
617
|
+
]);
|
|
618
|
+
return result.status === 0;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Method to check if a given sdkman tool is installed and available.
|
|
623
|
+
*
|
|
624
|
+
* @param {String} toolType Tool type such as java, gradle, maven etc.
|
|
625
|
+
* @param {String} toolName Tool name with version. Eg: 22.0.2-tem
|
|
626
|
+
*
|
|
627
|
+
* @returns {Boolean} true if the tool is available. false otherwise.
|
|
628
|
+
*/
|
|
629
|
+
export function isSdkmanToolAvailable(toolType, toolName) {
|
|
630
|
+
toolName = getSdkmanToolFullname(toolName);
|
|
631
|
+
let isToolAvailable =
|
|
632
|
+
readEnvironmentVariable("SDKMAN_CANDIDATES_DIR") &&
|
|
633
|
+
safeExistsSync(
|
|
634
|
+
join(
|
|
635
|
+
readEnvironmentVariable("SDKMAN_CANDIDATES_DIR"),
|
|
636
|
+
toolType,
|
|
637
|
+
toolName,
|
|
638
|
+
"bin",
|
|
639
|
+
),
|
|
640
|
+
);
|
|
641
|
+
if (
|
|
642
|
+
!isToolAvailable &&
|
|
643
|
+
safeExistsSync(
|
|
644
|
+
join(homedir(), ".sdkman", "candidates", toolType, toolName, "bin"),
|
|
645
|
+
)
|
|
646
|
+
) {
|
|
647
|
+
process.env.SDKMAN_CANDIDATES_DIR = join(
|
|
648
|
+
homedir(),
|
|
649
|
+
".sdkman",
|
|
650
|
+
"candidates",
|
|
651
|
+
);
|
|
652
|
+
isToolAvailable = true;
|
|
653
|
+
}
|
|
654
|
+
return isToolAvailable;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Method to install and use a given sdkman tool.
|
|
659
|
+
*
|
|
660
|
+
* @param {String} toolType Tool type such as java, gradle, maven etc.
|
|
661
|
+
* @param {String} toolName Tool name with version. Eg: 22.0.2-tem
|
|
662
|
+
*
|
|
663
|
+
* @returns {Boolean} true if the tool is available. false otherwise.
|
|
664
|
+
*/
|
|
665
|
+
export function installSdkmanTool(toolType, toolName) {
|
|
666
|
+
if (isWin) {
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
toolName = getSdkmanToolFullname(toolName);
|
|
670
|
+
let result;
|
|
671
|
+
if (!isSdkmanToolAvailable(toolType, toolName)) {
|
|
672
|
+
let installDir = "";
|
|
673
|
+
if (readEnvironmentVariable("SDKMAN_CANDIDATES_DIR")) {
|
|
674
|
+
installDir = join(
|
|
675
|
+
readEnvironmentVariable("SDKMAN_CANDIDATES_DIR"),
|
|
676
|
+
toolType,
|
|
677
|
+
);
|
|
678
|
+
}
|
|
679
|
+
console.log("About to install", toolType, toolName, installDir);
|
|
680
|
+
result = safeSpawnSync(readEnvironmentVariable("SHELL") || "bash", [
|
|
681
|
+
"-i",
|
|
682
|
+
"-c",
|
|
683
|
+
`echo -e "no" | sdk install ${toolType} ${toolName} ${installDir}`.trim(),
|
|
684
|
+
]);
|
|
685
|
+
if (DEBUG_MODE) {
|
|
686
|
+
if (result.stdout) {
|
|
687
|
+
console.log(result.stdout);
|
|
688
|
+
}
|
|
689
|
+
if (result.stderr) {
|
|
690
|
+
console.log(result.stderr);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
if (result.status === 1 || result.error) {
|
|
694
|
+
console.log(
|
|
695
|
+
"Unable to install",
|
|
696
|
+
toolType,
|
|
697
|
+
toolName,
|
|
698
|
+
"due to below errors.",
|
|
699
|
+
);
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const toolUpper = toolType.toUpperCase();
|
|
704
|
+
// Set process env variables
|
|
705
|
+
if (readEnvironmentVariable(`${toolUpper}_HOME`)?.includes("current")) {
|
|
706
|
+
process.env[`${toolUpper}_HOME`] = process.env[`${toolUpper}_HOME`].replace(
|
|
707
|
+
"current",
|
|
708
|
+
toolName,
|
|
709
|
+
);
|
|
710
|
+
console.log(
|
|
711
|
+
`${toolUpper}_HOME`,
|
|
712
|
+
"set to",
|
|
713
|
+
readEnvironmentVariable(`${toolUpper}_HOME`),
|
|
714
|
+
);
|
|
715
|
+
} else if (
|
|
716
|
+
readEnvironmentVariable("SDKMAN_CANDIDATES_DIR") &&
|
|
717
|
+
safeExistsSync(
|
|
718
|
+
join(
|
|
719
|
+
readEnvironmentVariable("SDKMAN_CANDIDATES_DIR"),
|
|
720
|
+
toolType,
|
|
721
|
+
toolName,
|
|
722
|
+
),
|
|
723
|
+
)
|
|
724
|
+
) {
|
|
725
|
+
process.env[`${toolUpper}_HOME`] = join(
|
|
726
|
+
readEnvironmentVariable("SDKMAN_CANDIDATES_DIR"),
|
|
727
|
+
toolType,
|
|
728
|
+
toolName,
|
|
729
|
+
);
|
|
730
|
+
console.log(
|
|
731
|
+
`${toolUpper}_HOME`,
|
|
732
|
+
"set to",
|
|
733
|
+
readEnvironmentVariable(`${toolUpper}_HOME`),
|
|
734
|
+
);
|
|
735
|
+
} else {
|
|
736
|
+
console.log(
|
|
737
|
+
"Directory",
|
|
738
|
+
join(
|
|
739
|
+
readEnvironmentVariable("SDKMAN_CANDIDATES_DIR"),
|
|
740
|
+
toolType,
|
|
741
|
+
toolName,
|
|
742
|
+
),
|
|
743
|
+
"is not found",
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
const toolCurrentBin = join(toolType, "current", "bin");
|
|
747
|
+
if (readEnvironmentVariable("PATH").includes(toolCurrentBin)) {
|
|
748
|
+
process.env.PATH = process.env.PATH.replace(
|
|
749
|
+
toolCurrentBin,
|
|
750
|
+
join(toolType, toolName, "bin"),
|
|
751
|
+
);
|
|
752
|
+
} else if (readEnvironmentVariable("SDKMAN_CANDIDATES_DIR")) {
|
|
753
|
+
const fullToolBinDir = join(
|
|
754
|
+
readEnvironmentVariable("SDKMAN_CANDIDATES_DIR"),
|
|
755
|
+
toolType,
|
|
756
|
+
toolName,
|
|
757
|
+
"bin",
|
|
758
|
+
);
|
|
759
|
+
if (!readEnvironmentVariable("PATH")?.includes(fullToolBinDir)) {
|
|
760
|
+
process.env.PATH = `${fullToolBinDir}${delimiter}${process.env.PATH}`;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return true;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Method to check if a given nvm tool is installed and available.
|
|
768
|
+
*
|
|
769
|
+
* @param {String} toolName Tool name with version. Eg: 22.0.2-tem
|
|
770
|
+
*
|
|
771
|
+
* @returns {String} path of nvm if present, otherwise false
|
|
772
|
+
*/
|
|
773
|
+
export function getNvmToolDirectory(toolName) {
|
|
774
|
+
const resultWhichNode = safeSpawnSync(
|
|
775
|
+
readEnvironmentVariable("SHELL") || "bash",
|
|
776
|
+
["-i", "-c", `nvm which ${toolName}`],
|
|
777
|
+
);
|
|
778
|
+
if (DEBUG_MODE) {
|
|
779
|
+
if (resultWhichNode.stdout) {
|
|
780
|
+
console.log(resultWhichNode.stdout);
|
|
781
|
+
}
|
|
782
|
+
if (resultWhichNode.stderr) {
|
|
783
|
+
console.log(resultWhichNode.stderr);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (resultWhichNode.status !== 0) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
// An interactive shell without a controlling terminal writes job control
|
|
790
|
+
// notices to stderr, so only stdout can tell us whether nvm resolved the
|
|
791
|
+
// version. Startup files may also print banners, hence the last path line.
|
|
792
|
+
const nodePath = (resultWhichNode.stdout || "")
|
|
793
|
+
.toString()
|
|
794
|
+
.split(/\r?\n/)
|
|
795
|
+
.map((line) => line.trim())
|
|
796
|
+
.filter((line) => line.startsWith("/"))
|
|
797
|
+
.pop();
|
|
798
|
+
if (!nodePath) {
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
return dirname(nodePath);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Method to return nvm tool path
|
|
807
|
+
*
|
|
808
|
+
* @param {String} toolVersion Tool name with version. Eg: 22.0.2-tem
|
|
809
|
+
*
|
|
810
|
+
* @returns {String} path of the tool if not found installs and then returns paths. false if encounters an error.
|
|
811
|
+
*/
|
|
812
|
+
export function getOrInstallNvmTool(toolVersion) {
|
|
813
|
+
const nvmNodePath = getNvmToolDirectory(toolVersion);
|
|
814
|
+
if (!nvmNodePath) {
|
|
815
|
+
// nvm couldn't directly use toolName so maybe needs to be installed
|
|
816
|
+
const resultInstall = safeSpawnSync(
|
|
817
|
+
readEnvironmentVariable("SHELL") || "bash",
|
|
818
|
+
["-i", "-c", `nvm install ${toolVersion}`],
|
|
819
|
+
);
|
|
820
|
+
|
|
821
|
+
if (DEBUG_MODE) {
|
|
822
|
+
if (resultInstall.stdout) {
|
|
823
|
+
console.log(resultInstall.stdout);
|
|
824
|
+
}
|
|
825
|
+
if (resultInstall.stderr) {
|
|
826
|
+
console.log(resultInstall.stderr);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
if (resultInstall.status !== 0) {
|
|
831
|
+
// There was some problem install the tool
|
|
832
|
+
// output has already been printed out
|
|
833
|
+
return false;
|
|
834
|
+
}
|
|
835
|
+
const nvmNodePath = getNvmToolDirectory(toolVersion);
|
|
836
|
+
if (nvmNodePath) {
|
|
837
|
+
return nvmNodePath;
|
|
838
|
+
}
|
|
839
|
+
return false;
|
|
840
|
+
}
|
|
841
|
+
return nvmNodePath;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* Retrieve sdkman tool full name
|
|
846
|
+
*/
|
|
847
|
+
function getSdkmanToolFullname(toolName) {
|
|
848
|
+
return SDKMAN_JAVA_TOOL_ALIASES[toolName] || toolName;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Method to check if rbenv is available.
|
|
853
|
+
*
|
|
854
|
+
* @returns {Boolean} true if rbenv is available. false otherwise.
|
|
855
|
+
*/
|
|
856
|
+
export function isRbenvAvailable() {
|
|
857
|
+
let result = safeSpawnSync(readEnvironmentVariable("SHELL") || "bash", [
|
|
858
|
+
"-i",
|
|
859
|
+
"-c",
|
|
860
|
+
`${readEnvironmentVariable("RBENV_CMD") || "rbenv"} --version`,
|
|
861
|
+
]);
|
|
862
|
+
if (result.status !== 0) {
|
|
863
|
+
result = safeSpawnSync(
|
|
864
|
+
readEnvironmentVariable("RBENV_CMD") || "rbenv",
|
|
865
|
+
["--version"],
|
|
866
|
+
{
|
|
867
|
+
shell: isWin,
|
|
868
|
+
},
|
|
869
|
+
);
|
|
870
|
+
return result.status === 0;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Returns the rbenv binary directory for the given Ruby version.
|
|
876
|
+
* Respects the `RBENV_ROOT` environment variable when set; otherwise falls back
|
|
877
|
+
* to `~/.rbenv/versions/<rubyVersion>/bin`.
|
|
878
|
+
*
|
|
879
|
+
* @param {string} rubyVersion Ruby version string (e.g. `"3.2.2"`)
|
|
880
|
+
* @returns {string} Absolute path to the rbenv bin directory for that version
|
|
881
|
+
*/
|
|
882
|
+
export function rubyVersionDir(rubyVersion) {
|
|
883
|
+
return readEnvironmentVariable("RBENV_ROOT")
|
|
884
|
+
? join(
|
|
885
|
+
readEnvironmentVariable("RBENV_ROOT"),
|
|
886
|
+
"versions",
|
|
887
|
+
rubyVersion,
|
|
888
|
+
"bin",
|
|
889
|
+
)
|
|
890
|
+
: join(homedir(), ".rbenv", "versions", rubyVersion, "bin");
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Perform bundle install using Ruby container images. Not working cleanly yet.
|
|
895
|
+
*
|
|
896
|
+
* @param rubyVersion Ruby version
|
|
897
|
+
* @param cdxgenGemHome Gem Home
|
|
898
|
+
* @param filePath Path
|
|
899
|
+
*/
|
|
900
|
+
export function bundleInstallWithDocker(rubyVersion, cdxgenGemHome, filePath) {
|
|
901
|
+
const ociCmd = readEnvironmentVariable("DOCKER_CMD") || "docker";
|
|
902
|
+
const ociArgs = [
|
|
903
|
+
"run",
|
|
904
|
+
"--rm",
|
|
905
|
+
"-e",
|
|
906
|
+
"GEM_HOME=/gems",
|
|
907
|
+
"-v",
|
|
908
|
+
`/tmp:${getTmpDir()}:rw`,
|
|
909
|
+
"-v",
|
|
910
|
+
`${filePath}:/app:rw`,
|
|
911
|
+
"-v",
|
|
912
|
+
`${cdxgenGemHome}:/gems:rw`,
|
|
913
|
+
"-w",
|
|
914
|
+
"/app",
|
|
915
|
+
"-it",
|
|
916
|
+
`docker.io/ruby:${rubyVersion}`,
|
|
917
|
+
"bash",
|
|
918
|
+
"-c",
|
|
919
|
+
"bundle",
|
|
920
|
+
"install",
|
|
921
|
+
];
|
|
922
|
+
console.log(`Performing bundle install with: ${ociCmd}`);
|
|
923
|
+
// The container's own output is a diagnostic. Inheriting stdout would let it
|
|
924
|
+
// interleave with the BOM document when the caller asked for `-o -`, so the
|
|
925
|
+
// child's stdout is pointed at the diagnostic stream instead.
|
|
926
|
+
const result = safeSpawnSync(ociCmd, ociArgs, {
|
|
927
|
+
shell: isWin,
|
|
928
|
+
stdio: ["inherit", diagnosticStream, "inherit"],
|
|
929
|
+
});
|
|
930
|
+
if (result.error || result.status !== 0) {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
if (safeExistsSync(join(filePath, "Gemfile.lock"))) {
|
|
934
|
+
console.log(
|
|
935
|
+
"Gemfile.lock was generated successfully. Thank you for trying this feature!",
|
|
936
|
+
);
|
|
937
|
+
}
|
|
938
|
+
return result.status === 0;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* Install a particular ruby version using rbenv.
|
|
943
|
+
*
|
|
944
|
+
* @param rubyVersion Ruby version to install
|
|
945
|
+
* @param filePath File path
|
|
946
|
+
*/
|
|
947
|
+
export function installRubyVersion(rubyVersion, filePath) {
|
|
948
|
+
if (!rubyVersion) {
|
|
949
|
+
return { fullToolBinDir: undefined, status: false };
|
|
950
|
+
}
|
|
951
|
+
const existingRuby = collectRubyInfo(filePath);
|
|
952
|
+
if (existingRuby?.version?.startsWith(`ruby ${rubyVersion} `)) {
|
|
953
|
+
return { fullToolBinDir: undefined, status: true };
|
|
954
|
+
}
|
|
955
|
+
const fullToolBinDir = rubyVersionDir(rubyVersion);
|
|
956
|
+
if (safeExistsSync(fullToolBinDir)) {
|
|
957
|
+
const result = safeSpawnSync(
|
|
958
|
+
readEnvironmentVariable("RBENV_CMD") || "rbenv",
|
|
959
|
+
["local", rubyVersion],
|
|
960
|
+
{
|
|
961
|
+
shell: isWin,
|
|
962
|
+
},
|
|
963
|
+
);
|
|
964
|
+
if (result.error || result.status !== 0) {
|
|
965
|
+
if (result.stdout) {
|
|
966
|
+
console.log(result.stdout);
|
|
967
|
+
}
|
|
968
|
+
if (result.stderr) {
|
|
969
|
+
console.log(result.stderr);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
if (result.status === 0) {
|
|
973
|
+
return { fullToolBinDir, status: true };
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
// Check if we're trying to install Ruby 1.x or 2.x
|
|
977
|
+
if (rubyVersion.startsWith("1.")) {
|
|
978
|
+
console.log(
|
|
979
|
+
`Ruby version ${rubyVersion} requires very old versions of Linux such as debian:8. Consider using the container image "ghcr.io/cdxgen/debian-ruby18:master" to build the application first and then invoke cdxgen with the arguments "--lifecycle pre-build".`,
|
|
980
|
+
);
|
|
981
|
+
console.log("The below install step is likely to fail.");
|
|
982
|
+
} else if (
|
|
983
|
+
rubyVersion.startsWith("2.") &&
|
|
984
|
+
readEnvironmentVariable("CDXGEN_IN_CONTAINER") !== "true"
|
|
985
|
+
) {
|
|
986
|
+
console.log(
|
|
987
|
+
`Installing Ruby version ${rubyVersion} requires specific development libraries. Consider using the custom container image "ghcr.io/cdxgen/cdxgen-debian-ruby26:v13" instead.`,
|
|
988
|
+
);
|
|
989
|
+
console.log("The below install step is likely to fail.");
|
|
990
|
+
}
|
|
991
|
+
console.log(
|
|
992
|
+
`Attempting to install Ruby ${rubyVersion} using rbenv. This might take a while ...`,
|
|
993
|
+
);
|
|
994
|
+
if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") === "true") {
|
|
995
|
+
console.log(
|
|
996
|
+
`To speed up this step, use bind mounts. Example: "--mount type=bind,src=/tmp/rbenv,dst=/root/.rbenv/versions/${rubyVersion}"`,
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
const result = safeSpawnSync(
|
|
1000
|
+
readEnvironmentVariable("RBENV_CMD") || "rbenv",
|
|
1001
|
+
["install", rubyVersion],
|
|
1002
|
+
{
|
|
1003
|
+
shell: isWin,
|
|
1004
|
+
},
|
|
1005
|
+
);
|
|
1006
|
+
if (result.error || result.status !== 0) {
|
|
1007
|
+
if (result.stdout) {
|
|
1008
|
+
console.log(result.stdout);
|
|
1009
|
+
}
|
|
1010
|
+
if (result.stderr) {
|
|
1011
|
+
console.log(result.stderr);
|
|
1012
|
+
}
|
|
1013
|
+
if (isMac) {
|
|
1014
|
+
console.log(
|
|
1015
|
+
"Try running the commands `sudo xcode-select --install` followed by `xcodebuild -runFirstLaunch`.",
|
|
1016
|
+
);
|
|
1017
|
+
console.log(
|
|
1018
|
+
"TIP: Run the command `brew info ruby` and follow the instructions to set the environment variables sLDFLAGS, CPPFLAGS, and PKG_CONFIG_PATH.",
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") === "true") {
|
|
1022
|
+
console.log(
|
|
1023
|
+
"Are there any devel packages that could be included in the cdxgen container image to avoid these errors? Start a discussion thread here: https://github.com/cdxgen/cdxgen/discussions",
|
|
1024
|
+
);
|
|
1025
|
+
} else {
|
|
1026
|
+
console.log(
|
|
1027
|
+
`TIP: Try using the custom container image "ghcr.io/cdxgen/cdxgen-debian-ruby34" with the argument "-t ruby${rubyVersion}"`,
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return { fullToolBinDir, status: result.status === 0 };
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* Method to install bundler using gem.
|
|
1036
|
+
*
|
|
1037
|
+
* @param rubyVersion Ruby version
|
|
1038
|
+
* @param bundlerVersion Bundler version
|
|
1039
|
+
*/
|
|
1040
|
+
export function installRubyBundler(rubyVersion, bundlerVersion) {
|
|
1041
|
+
const minRubyVersion = "3.1.0";
|
|
1042
|
+
let bundlerWarningShown = false;
|
|
1043
|
+
if (!bundlerVersion && compareLoose(rubyVersion, minRubyVersion) === -1) {
|
|
1044
|
+
console.log(
|
|
1045
|
+
`Default installation for bundler requires Ruby >= ${minRubyVersion}. Attempting to detect and install an older version of bundler for Ruby ${rubyVersion}.`,
|
|
1046
|
+
);
|
|
1047
|
+
bundlerWarningShown = true;
|
|
1048
|
+
}
|
|
1049
|
+
const fullToolBinDir = rubyVersionDir(rubyVersion);
|
|
1050
|
+
if (safeExistsSync(fullToolBinDir)) {
|
|
1051
|
+
const gemInstallArgs = ["install", "bundler"];
|
|
1052
|
+
if (bundlerVersion) {
|
|
1053
|
+
gemInstallArgs.push("-v");
|
|
1054
|
+
gemInstallArgs.push(bundlerVersion);
|
|
1055
|
+
}
|
|
1056
|
+
if (!bundlerWarningShown) {
|
|
1057
|
+
if (bundlerVersion) {
|
|
1058
|
+
console.log(
|
|
1059
|
+
`Installing bundler ${bundlerVersion} using ${join(fullToolBinDir, "gem")}`,
|
|
1060
|
+
);
|
|
1061
|
+
} else {
|
|
1062
|
+
console.log(
|
|
1063
|
+
`Installing bundler using ${join(fullToolBinDir, "gem")} ${gemInstallArgs.join(" ")}`,
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
const result = safeSpawnSync(join(fullToolBinDir, "gem"), gemInstallArgs, {
|
|
1068
|
+
shell: isWin,
|
|
1069
|
+
});
|
|
1070
|
+
if (bundlerWarningShown) {
|
|
1071
|
+
if (result.stderr?.includes("Try installing it with")) {
|
|
1072
|
+
const oldBundlerVersion = result.stderr
|
|
1073
|
+
.split("`\n")[0]
|
|
1074
|
+
.split("Try installing it with `")
|
|
1075
|
+
.pop()
|
|
1076
|
+
.split(" ")
|
|
1077
|
+
.pop()
|
|
1078
|
+
.replaceAll("`", "");
|
|
1079
|
+
if (/^\d+/.test(oldBundlerVersion)) {
|
|
1080
|
+
console.log(
|
|
1081
|
+
`The last version of bundler to support your Ruby & RubyGems was ${oldBundlerVersion}. cdxgen will now attempt to install this version.`,
|
|
1082
|
+
);
|
|
1083
|
+
return installRubyBundler(rubyVersion, oldBundlerVersion);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
} else {
|
|
1087
|
+
if (result.error || result.status !== 0) {
|
|
1088
|
+
if (result.stdout) {
|
|
1089
|
+
console.log(result.stdout);
|
|
1090
|
+
}
|
|
1091
|
+
if (result.stderr) {
|
|
1092
|
+
console.log(result.stderr);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
return result.status === 0;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
return false;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/**
|
|
1102
|
+
* Method to perform bundle install
|
|
1103
|
+
*
|
|
1104
|
+
* @param cdxgenGemHome cdxgen Gem home
|
|
1105
|
+
* @param rubyVersion Ruby version
|
|
1106
|
+
* @param bundleCommand Bundle command to use
|
|
1107
|
+
* @param basePath working directory
|
|
1108
|
+
*
|
|
1109
|
+
* @returns {boolean} true if the install was successful. false otherwise.
|
|
1110
|
+
*/
|
|
1111
|
+
export function performBundleInstall(
|
|
1112
|
+
cdxgenGemHome,
|
|
1113
|
+
rubyVersion,
|
|
1114
|
+
bundleCommand,
|
|
1115
|
+
basePath,
|
|
1116
|
+
) {
|
|
1117
|
+
if (arch() !== "x64") {
|
|
1118
|
+
console.log(
|
|
1119
|
+
`INFO: Many Ruby packages have limited support for ${arch()} architecture. Run the cdxgen container image with --platform=linux/amd64 for best experience.`,
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
let installArgs = ["install"];
|
|
1123
|
+
if (readEnvironmentVariable("BUNDLE_INSTALL_ARGS")) {
|
|
1124
|
+
installArgs = installArgs.concat(
|
|
1125
|
+
readEnvironmentVariable("BUNDLE_INSTALL_ARGS").split(" "),
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
const gemFileLock = join(basePath, "Gemfile.lock");
|
|
1129
|
+
console.log(
|
|
1130
|
+
`Invoking ${bundleCommand} ${installArgs.join(" ")} from ${basePath} with GEM_HOME ${cdxgenGemHome}. Please wait ...`,
|
|
1131
|
+
);
|
|
1132
|
+
let result = safeSpawnSync(bundleCommand, installArgs, {
|
|
1133
|
+
shell: isWin,
|
|
1134
|
+
cwd: basePath,
|
|
1135
|
+
env: {
|
|
1136
|
+
...process.env,
|
|
1137
|
+
GEM_HOME: cdxgenGemHome,
|
|
1138
|
+
},
|
|
1139
|
+
});
|
|
1140
|
+
if (result.error || result.status !== 0) {
|
|
1141
|
+
let pythonWarningShown = false;
|
|
1142
|
+
let rubyVersionWarningShown = false;
|
|
1143
|
+
if (
|
|
1144
|
+
result?.stderr?.includes("requires python 2 to be installed") ||
|
|
1145
|
+
result?.stdout?.includes("requires python 2 to be installed")
|
|
1146
|
+
) {
|
|
1147
|
+
pythonWarningShown = true;
|
|
1148
|
+
console.log(
|
|
1149
|
+
"A native module requires python 2 to be installed. Please install python 2.7.18 from https://www.python.org/downloads/release/python-2718/.",
|
|
1150
|
+
);
|
|
1151
|
+
console.log(
|
|
1152
|
+
"NOTE: Python 2.7.x has now reached end-of-life. Python 2.7.18, is the FINAL RELEASE of Python 2.7.x. It will no longer be supported or updated. You should stop using this project in production and decommission immediately.",
|
|
1153
|
+
);
|
|
1154
|
+
console.log(
|
|
1155
|
+
"Further, the project might need older versions of gcc and other build tools which might not be readily available in this environment.",
|
|
1156
|
+
);
|
|
1157
|
+
if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") === "true") {
|
|
1158
|
+
console.log(
|
|
1159
|
+
"cdxgen container images do not bundle Python 2. Run cdxgen in cli mode to proceed with the SBOM generation.",
|
|
1160
|
+
);
|
|
1161
|
+
}
|
|
1162
|
+
console.log(
|
|
1163
|
+
"Alternatively, ensure Gemfile.lock is present locally and invoke cdxgen with the argument `--lifecycle pre-build`.",
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
if (
|
|
1167
|
+
result?.stderr?.includes("Running `bundle update ") ||
|
|
1168
|
+
result?.stdout?.includes("Running `bundle update ")
|
|
1169
|
+
) {
|
|
1170
|
+
console.log(
|
|
1171
|
+
"Gemfile.lock appears to be outdated. Attempting automated update.",
|
|
1172
|
+
);
|
|
1173
|
+
const packageToUpdate = result.stderr
|
|
1174
|
+
.split("Running `bundle update ")
|
|
1175
|
+
.pop()
|
|
1176
|
+
.split("`")[0];
|
|
1177
|
+
let updateArgs = ["update"];
|
|
1178
|
+
if (packageToUpdate?.length && !packageToUpdate.includes(" ")) {
|
|
1179
|
+
updateArgs.push(packageToUpdate);
|
|
1180
|
+
}
|
|
1181
|
+
if (readEnvironmentVariable("BUNDLE_UPDATE_ARGS")) {
|
|
1182
|
+
updateArgs = updateArgs.concat(
|
|
1183
|
+
readEnvironmentVariable("BUNDLE_UPDATE_ARGS").split(" "),
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
console.log(`${bundleCommand}`);
|
|
1187
|
+
result = safeSpawnSync(bundleCommand, updateArgs, {
|
|
1188
|
+
shell: isWin,
|
|
1189
|
+
cwd: basePath,
|
|
1190
|
+
env: {
|
|
1191
|
+
...process.env,
|
|
1192
|
+
GEM_HOME: cdxgenGemHome,
|
|
1193
|
+
},
|
|
1194
|
+
});
|
|
1195
|
+
if (result.error || result.status !== 0) {
|
|
1196
|
+
console.log("------------");
|
|
1197
|
+
if (result.stdout) {
|
|
1198
|
+
console.log(result.stdout);
|
|
1199
|
+
}
|
|
1200
|
+
if (result.stderr) {
|
|
1201
|
+
console.log(result.stderr);
|
|
1202
|
+
}
|
|
1203
|
+
console.log("------------");
|
|
1204
|
+
}
|
|
1205
|
+
return result.status === 0;
|
|
1206
|
+
}
|
|
1207
|
+
if (
|
|
1208
|
+
result?.stderr?.includes("Your Ruby version is ") ||
|
|
1209
|
+
result?.stdout?.includes("Your Ruby version is ")
|
|
1210
|
+
) {
|
|
1211
|
+
console.log(
|
|
1212
|
+
"This project requires a specific version of Ruby. The version requirements can be found in the error message below.",
|
|
1213
|
+
);
|
|
1214
|
+
rubyVersionWarningShown = true;
|
|
1215
|
+
}
|
|
1216
|
+
if (result?.stderr?.includes("requires rubygems version")) {
|
|
1217
|
+
console.log(
|
|
1218
|
+
"This project requires a specific version of RubyGems. To do this, the existing version must be uninstalled followed by installing the required version. `sudo gem uninstall rubygems-update -v <existing version>` and then `sudo gem install rubygems-update -v <required version>`.",
|
|
1219
|
+
);
|
|
1220
|
+
rubyVersionWarningShown = true;
|
|
1221
|
+
if (safeExistsSync(gemFileLock)) {
|
|
1222
|
+
console.log("Run `bundle install` command to troubleshoot the build.");
|
|
1223
|
+
} else {
|
|
1224
|
+
console.log(
|
|
1225
|
+
"Try building this project directly and set the environment variable CDXGEN_GEM_HOME with the gems directory. Look for any Dockerfile or CI workflow files for information regarding the exact version of Ruby, RubyGems, Bundler needed to build this project.",
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") === "true") {
|
|
1229
|
+
console.log(
|
|
1230
|
+
"TIP: Create your own container image by using an existing Ruby base image from here: https://github.com/cdxgen/cdxgen/tree/master/ci/images/debian",
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
if (result?.stderr?.includes("Bundler cannot continue")) {
|
|
1235
|
+
console.log(
|
|
1236
|
+
'Bundle install is unable to continue due to a dependency resolution and build issue. Running bundle install without certain groups might work in such instances. Try running cdxgen with the environment variable `BUNDLE_INSTALL_ARGS`. Example: to skip `test` group, set the variable `"BUNDLE_INSTALL_ARGS=--without test"`',
|
|
1237
|
+
);
|
|
1238
|
+
console.log(
|
|
1239
|
+
"NOTE: The generated SBOM would be incomplete with this workaround.",
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
if (result?.stderr?.includes("Target architecture x64 is only supported")) {
|
|
1243
|
+
console.log(
|
|
1244
|
+
"A gem native extension requires x64/amd64 architecture. Run the cdxgen container image with the argument '--platform=linux/amd64'.",
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
if (
|
|
1248
|
+
!pythonWarningShown &&
|
|
1249
|
+
(result?.stderr?.includes("Failed to build gem native extension") ||
|
|
1250
|
+
result?.stderr?.includes("Gem::Ext::BuildError"))
|
|
1251
|
+
) {
|
|
1252
|
+
console.log(
|
|
1253
|
+
"Bundler failed to build some gem native extension(s). Carefully review the below error to install any required development libraries.",
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
console.log("------------");
|
|
1257
|
+
if (result.stdout) {
|
|
1258
|
+
console.log(result.stdout);
|
|
1259
|
+
}
|
|
1260
|
+
if (result.stderr) {
|
|
1261
|
+
console.log(result.stderr);
|
|
1262
|
+
}
|
|
1263
|
+
console.log("------------");
|
|
1264
|
+
if (
|
|
1265
|
+
readEnvironmentVariable("CDXGEN_IN_CONTAINER") === "true" &&
|
|
1266
|
+
!rubyVersionWarningShown
|
|
1267
|
+
) {
|
|
1268
|
+
console.log(
|
|
1269
|
+
"Are there any devel packages that could be included in the cdxgen container image to avoid these errors? Start a discussion thread here: https://github.com/cdxgen/cdxgen/discussions",
|
|
1270
|
+
);
|
|
1271
|
+
console.log("------------");
|
|
1272
|
+
} else if (rubyVersion) {
|
|
1273
|
+
console.log(
|
|
1274
|
+
`TIP: Try using the custom container image "ghcr.io/cdxgen/cdxgen-debian-ruby34" with the argument "-t ruby${rubyVersion}".`,
|
|
1275
|
+
);
|
|
1276
|
+
} else {
|
|
1277
|
+
console.log(
|
|
1278
|
+
`TIP: Try invoking cdxgen with a Ruby version type. With the custom container image "ghcr.io/cdxgen/cdxgen-debian-ruby34", you can pass the argument "-t ruby<version>". Example: "-t ruby3.3.6"`,
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
return result.status === 0;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
/**
|
|
1286
|
+
* Validates if a git ref name is safe to use in commands.
|
|
1287
|
+
*
|
|
1288
|
+
* @param {string} refName The git ref name to check
|
|
1289
|
+
* @returns {boolean} True if the ref name is safe, false otherwise
|
|
1290
|
+
*/
|
|
1291
|
+
function isSafeRef(refName) {
|
|
1292
|
+
if (!refName || typeof refName !== "string") {
|
|
1293
|
+
return false;
|
|
1294
|
+
}
|
|
1295
|
+
if (refName.startsWith("-")) {
|
|
1296
|
+
return false;
|
|
1297
|
+
}
|
|
1298
|
+
return /^[A-Za-z0-9._/@+-]+$/.test(refName);
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
// Upper bound for the commit window so a caller-supplied count cannot blow up
|
|
1302
|
+
// the git invocation.
|
|
1303
|
+
const MAX_GIT_LOG_COUNT = 100000;
|
|
1304
|
+
|
|
1305
|
+
/**
|
|
1306
|
+
* Coerce a caller-supplied commit count into a safe, bounded positive integer.
|
|
1307
|
+
* The result is always a plain integer, so it can never carry shell
|
|
1308
|
+
* metacharacters into the (potentially shell-invoked, on Windows) git command.
|
|
1309
|
+
*
|
|
1310
|
+
* @param {*} maxCount Requested commit count (may be any type)
|
|
1311
|
+
* @param {number} [fallback] Default when the value is missing/invalid
|
|
1312
|
+
* @returns {number} A positive integer in [1, MAX_GIT_LOG_COUNT]
|
|
1313
|
+
*/
|
|
1314
|
+
function safeGitLogCount(maxCount, fallback = 20) {
|
|
1315
|
+
const n = Number.parseInt(maxCount, 10);
|
|
1316
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
1317
|
+
return fallback;
|
|
1318
|
+
}
|
|
1319
|
+
return Math.min(n, MAX_GIT_LOG_COUNT);
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* Validates that a commit-ish (hash or ref) is safe to place in a git command.
|
|
1324
|
+
* Reuses the ref charset (alphanumerics, `._/@+-`, no leading `-`), which also
|
|
1325
|
+
* covers hex object names and symbolic refs such as `HEAD`.
|
|
1326
|
+
*
|
|
1327
|
+
* @param {string} commitish Commit hash or ref
|
|
1328
|
+
* @returns {boolean} True when safe to use as a git argument
|
|
1329
|
+
*/
|
|
1330
|
+
function isSafeCommitish(commitish) {
|
|
1331
|
+
return isSafeRef(commitish);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
/**
|
|
1335
|
+
* Retrieves the commit logs for a git repo with detailed author, committer, parents, signatures, and body.
|
|
1336
|
+
*
|
|
1337
|
+
* @param {string} dir Repo directory
|
|
1338
|
+
* @param {number} maxCount Maximum number of commits to retrieve
|
|
1339
|
+
* @returns {Array<Object>} Array of detailed commit objects
|
|
1340
|
+
*/
|
|
1341
|
+
export function gitLogCommitsDetailed(dir, maxCount = 20) {
|
|
1342
|
+
const count = safeGitLogCount(maxCount);
|
|
1343
|
+
const output = execGitCommand(dir, [
|
|
1344
|
+
"log",
|
|
1345
|
+
"-n",
|
|
1346
|
+
`${count}`,
|
|
1347
|
+
"--format=%H%n%an%n%ae%n%cn%n%ce%n%P%n%G?%n%B%x1e",
|
|
1348
|
+
]);
|
|
1349
|
+
if (!output) {
|
|
1350
|
+
return [];
|
|
1351
|
+
}
|
|
1352
|
+
const commits = [];
|
|
1353
|
+
const parts = output.split("\x1e");
|
|
1354
|
+
for (const part of parts) {
|
|
1355
|
+
const trimmed = part.trim();
|
|
1356
|
+
if (!trimmed) {
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
const lines = trimmed.split("\n");
|
|
1360
|
+
if (lines.length < 7) {
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
const hash = lines[0]?.trim();
|
|
1364
|
+
const authorName = lines[1]?.trim() || "";
|
|
1365
|
+
const authorEmail = lines[2]?.trim() || "";
|
|
1366
|
+
const committerName = lines[3]?.trim() || "";
|
|
1367
|
+
const committerEmail = lines[4]?.trim() || "";
|
|
1368
|
+
const parents = lines[5]?.trim() ? lines[5].trim().split(/\s+/) : [];
|
|
1369
|
+
const signatureStatus = lines[6]?.trim() || "N";
|
|
1370
|
+
const message = lines.slice(7).join("\n").trim();
|
|
1371
|
+
|
|
1372
|
+
// Check if Signed-off-by trailer is present
|
|
1373
|
+
const hasSignedOff = /signed-off-by:/i.test(message);
|
|
1374
|
+
|
|
1375
|
+
if (hash) {
|
|
1376
|
+
commits.push({
|
|
1377
|
+
hash,
|
|
1378
|
+
authorName,
|
|
1379
|
+
authorEmail,
|
|
1380
|
+
committerName,
|
|
1381
|
+
committerEmail,
|
|
1382
|
+
parents,
|
|
1383
|
+
signatureStatus,
|
|
1384
|
+
message,
|
|
1385
|
+
hasSignedOff,
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
return commits;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Determines whether a path looks like a test/spec file, using path-segment and
|
|
1394
|
+
* filename patterns rather than a naive substring match (which would flag files
|
|
1395
|
+
* such as `src/attestation.js` or `contest.py`).
|
|
1396
|
+
*
|
|
1397
|
+
* @param {string} filePath Repo-relative file path
|
|
1398
|
+
* @returns {boolean} True if the path is a test/spec source file
|
|
1399
|
+
*/
|
|
1400
|
+
function isTestPath(filePath) {
|
|
1401
|
+
if (!filePath) {
|
|
1402
|
+
return false;
|
|
1403
|
+
}
|
|
1404
|
+
return (
|
|
1405
|
+
/(^|\/)(tests?|specs?|__tests__|__mocks__|testing)\//i.test(filePath) ||
|
|
1406
|
+
/(^|\/)(test|spec)_[^/]+$/i.test(filePath) ||
|
|
1407
|
+
/[._-](test|spec|tests|specs)\.[A-Za-z0-9]+$/i.test(filePath)
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* Determines whether a path is a CI/build/script file where a bare `|| true`
|
|
1413
|
+
* suppression is a meaningful quality-gate-weakening signal.
|
|
1414
|
+
*
|
|
1415
|
+
* @param {string} filePath Repo-relative file path
|
|
1416
|
+
* @returns {boolean} True if the path is a CI/build/script file
|
|
1417
|
+
*/
|
|
1418
|
+
function isCiOrScriptPath(filePath) {
|
|
1419
|
+
if (!filePath) {
|
|
1420
|
+
return false;
|
|
1421
|
+
}
|
|
1422
|
+
return (
|
|
1423
|
+
filePath.includes(".github/workflows") ||
|
|
1424
|
+
/(^|\/)\.gitlab-ci\.yml$/i.test(filePath) ||
|
|
1425
|
+
/(^|\/)(Makefile|makefile|Justfile)$/.test(filePath) ||
|
|
1426
|
+
/\.(sh|bash|bat|ps1|mk)$/i.test(filePath) ||
|
|
1427
|
+
filePath.endsWith("package.json") ||
|
|
1428
|
+
/(azure-pipelines|\.circleci\/|Jenkinsfile|\.drone|bitbucket-pipelines)/i.test(
|
|
1429
|
+
filePath,
|
|
1430
|
+
)
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* High-signal quality-gate weakening tokens. These are conservative on purpose:
|
|
1436
|
+
* they only match constructs that intentionally silence failures or bypass
|
|
1437
|
+
* verification, to keep the false-positive rate low for ordinary refactors.
|
|
1438
|
+
*/
|
|
1439
|
+
const CI_WEAKENING_PATTERNS = [
|
|
1440
|
+
/continue-on-error\s*:\s*true/i,
|
|
1441
|
+
/--no-verify\b/,
|
|
1442
|
+
/HUSKY\s*=\s*0/,
|
|
1443
|
+
/--ignore-scripts\b/,
|
|
1444
|
+
/pytest\.mark\.skip\b/,
|
|
1445
|
+
];
|
|
1446
|
+
|
|
1447
|
+
/**
|
|
1448
|
+
* Runs a git show on a commit hash and analyzes the diff for test-file
|
|
1449
|
+
* deletions and quality-gate-weakening changes (e.g. `|| true`,
|
|
1450
|
+
* `continue-on-error: true`, `--no-verify`). Detection is intentionally
|
|
1451
|
+
* conservative to avoid false positives from ordinary refactors.
|
|
1452
|
+
*
|
|
1453
|
+
* @param {string} dir Repo directory
|
|
1454
|
+
* @param {string} commitHash Commit hash to analyze
|
|
1455
|
+
* @returns {Object} Commit diff analysis results
|
|
1456
|
+
*/
|
|
1457
|
+
export function gitCommitDiffAnalysis(dir, commitHash) {
|
|
1458
|
+
const empty = {
|
|
1459
|
+
testFilesDeleted: [],
|
|
1460
|
+
weakeningTokens: [],
|
|
1461
|
+
touchedFiles: [],
|
|
1462
|
+
addedLinesCount: 0,
|
|
1463
|
+
deletedLinesCount: 0,
|
|
1464
|
+
};
|
|
1465
|
+
// Reject anything that is not a safe commit-ish (hex hash or ref); this keeps
|
|
1466
|
+
// shell metacharacters and option-like values out of the git argument.
|
|
1467
|
+
if (!isSafeCommitish(commitHash)) {
|
|
1468
|
+
return empty;
|
|
1469
|
+
}
|
|
1470
|
+
// --no-ext-diff / --no-textconv block .gitattributes-driven external diff and
|
|
1471
|
+
// textconv drivers (arbitrary shell commands) from an untrusted repo.
|
|
1472
|
+
const output = execGitCommand(dir, [
|
|
1473
|
+
"show",
|
|
1474
|
+
"--no-ext-diff",
|
|
1475
|
+
"--no-textconv",
|
|
1476
|
+
commitHash,
|
|
1477
|
+
]);
|
|
1478
|
+
if (!output) {
|
|
1479
|
+
return empty;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
const testFilesDeleted = [];
|
|
1483
|
+
const weakeningTokens = [];
|
|
1484
|
+
const touchedFiles = [];
|
|
1485
|
+
let addedLinesCount = 0;
|
|
1486
|
+
let deletedLinesCount = 0;
|
|
1487
|
+
|
|
1488
|
+
// Parse the diff
|
|
1489
|
+
const lines = output.split("\n");
|
|
1490
|
+
let currentFile = "";
|
|
1491
|
+
let currentFileIsTest = false;
|
|
1492
|
+
let currentFileIsCi = false;
|
|
1493
|
+
|
|
1494
|
+
for (const line of lines) {
|
|
1495
|
+
// Check file headers
|
|
1496
|
+
if (line.startsWith("diff --git ")) {
|
|
1497
|
+
currentFile = "";
|
|
1498
|
+
currentFileIsTest = false;
|
|
1499
|
+
currentFileIsCi = false;
|
|
1500
|
+
const parts = line.split(" ");
|
|
1501
|
+
if (parts.length >= 4) {
|
|
1502
|
+
let file = parts[2];
|
|
1503
|
+
if (file.startsWith("a/")) {
|
|
1504
|
+
file = file.substring(2);
|
|
1505
|
+
}
|
|
1506
|
+
touchedFiles.push(file);
|
|
1507
|
+
currentFile = file;
|
|
1508
|
+
currentFileIsTest = isTestPath(file);
|
|
1509
|
+
currentFileIsCi = isCiOrScriptPath(file);
|
|
1510
|
+
}
|
|
1511
|
+
} else if (line.startsWith("--- a/")) {
|
|
1512
|
+
const oldFile = line.substring(6).trim();
|
|
1513
|
+
if (!currentFile) {
|
|
1514
|
+
currentFile = oldFile;
|
|
1515
|
+
currentFileIsTest = isTestPath(oldFile);
|
|
1516
|
+
currentFileIsCi = isCiOrScriptPath(oldFile);
|
|
1517
|
+
}
|
|
1518
|
+
} else if (line.startsWith("+++ /dev/null") && currentFileIsTest) {
|
|
1519
|
+
// Whole test file removed
|
|
1520
|
+
testFilesDeleted.push(currentFile);
|
|
1521
|
+
} else if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
1522
|
+
addedLinesCount++;
|
|
1523
|
+
// Quality-gate weakening tokens are only meaningful inside CI/build/script
|
|
1524
|
+
// config files. Matching them in arbitrary source or docs produces false
|
|
1525
|
+
// positives (e.g. a linter's own rule set, or documentation that merely
|
|
1526
|
+
// mentions `--no-verify`), so they are scoped to CI/script files.
|
|
1527
|
+
if (currentFileIsCi) {
|
|
1528
|
+
const addedContent = line.substring(1);
|
|
1529
|
+
if (
|
|
1530
|
+
CI_WEAKENING_PATTERNS.some((re) => re.test(addedContent)) ||
|
|
1531
|
+
/\|\|\s*true\b/.test(addedContent)
|
|
1532
|
+
) {
|
|
1533
|
+
weakeningTokens.push(addedContent.trim());
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
1537
|
+
deletedLinesCount++;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
return {
|
|
1542
|
+
testFilesDeleted,
|
|
1543
|
+
weakeningTokens,
|
|
1544
|
+
touchedFiles,
|
|
1545
|
+
addedLinesCount,
|
|
1546
|
+
deletedLinesCount,
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
/**
|
|
1551
|
+
* Retrieves the git-ai notes metadata for recent commits.
|
|
1552
|
+
*
|
|
1553
|
+
* @param {string} dir Repo directory
|
|
1554
|
+
* @param {Object} [options] Options for note retrieval
|
|
1555
|
+
* @param {string} [options.ref] Notes reference path (defaults to refs/notes/ai)
|
|
1556
|
+
* @param {number} [options.maxCount] Maximum commits to scan (defaults to 20)
|
|
1557
|
+
* @returns {Array<Object>} Array of note objects { hash, note }
|
|
1558
|
+
*/
|
|
1559
|
+
export function gitAiNotes(dir, options = {}) {
|
|
1560
|
+
const ref = options.ref || "refs/notes/ai";
|
|
1561
|
+
const maxCount = safeGitLogCount(options.maxCount);
|
|
1562
|
+
|
|
1563
|
+
if (!isSafeRef(ref)) {
|
|
1564
|
+
return [];
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
const output = execGitCommand(dir, [
|
|
1568
|
+
"log",
|
|
1569
|
+
"-n",
|
|
1570
|
+
`${maxCount}`,
|
|
1571
|
+
`--notes=${ref}`,
|
|
1572
|
+
"--format=%H%n%N%x1e",
|
|
1573
|
+
]);
|
|
1574
|
+
|
|
1575
|
+
if (!output) {
|
|
1576
|
+
return [];
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
const notes = [];
|
|
1580
|
+
const parts = output.split("\x1e");
|
|
1581
|
+
for (const part of parts) {
|
|
1582
|
+
const trimmed = part.trim();
|
|
1583
|
+
if (!trimmed) {
|
|
1584
|
+
continue;
|
|
1585
|
+
}
|
|
1586
|
+
const newlineIdx = trimmed.indexOf("\n");
|
|
1587
|
+
let hash = "";
|
|
1588
|
+
let noteContent = "";
|
|
1589
|
+
if (newlineIdx === -1) {
|
|
1590
|
+
hash = trimmed;
|
|
1591
|
+
} else {
|
|
1592
|
+
hash = trimmed.substring(0, newlineIdx).trim();
|
|
1593
|
+
noteContent = trimmed.substring(newlineIdx + 1).trim();
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
if (hash && noteContent) {
|
|
1597
|
+
notes.push({ hash, note: noteContent });
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
return notes;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
// Revert/hotfix/rollback intent in a commit subject. Scoped to the subject line
|
|
1604
|
+
// (not the full body) to avoid matching commits that merely discuss a revert.
|
|
1605
|
+
const REVERT_HOTFIX_RE = /\b(?:revert|roll[- ]?back|hot[- ]?fix)\b/i;
|
|
1606
|
+
|
|
1607
|
+
/**
|
|
1608
|
+
* Retrieves recent commits whose subject indicates a revert, hotfix, or
|
|
1609
|
+
* rollback. Bounded to the same recency window as the other collectors — unlike
|
|
1610
|
+
* `git log --grep`, which traverses the entire history looking for matches.
|
|
1611
|
+
*
|
|
1612
|
+
* @param {string} dir Repo directory
|
|
1613
|
+
* @param {number} maxCount Maximum number of recent commits to scan
|
|
1614
|
+
* @returns {Array<Object>} Array of { hash, message } revert/hotfix commits
|
|
1615
|
+
*/
|
|
1616
|
+
export function gitRevertsAndHotfixes(dir, maxCount = 20) {
|
|
1617
|
+
const count = safeGitLogCount(maxCount);
|
|
1618
|
+
const output = execGitCommand(dir, [
|
|
1619
|
+
"log",
|
|
1620
|
+
"-n",
|
|
1621
|
+
`${count}`,
|
|
1622
|
+
"--format=%H%n%B%x1e",
|
|
1623
|
+
]);
|
|
1624
|
+
|
|
1625
|
+
if (!output) {
|
|
1626
|
+
return [];
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
const entries = [];
|
|
1630
|
+
const parts = output.split("\x1e");
|
|
1631
|
+
for (const part of parts) {
|
|
1632
|
+
const trimmed = part.trim();
|
|
1633
|
+
if (!trimmed) {
|
|
1634
|
+
continue;
|
|
1635
|
+
}
|
|
1636
|
+
const lines = trimmed.split("\n");
|
|
1637
|
+
const hash = lines[0]?.trim();
|
|
1638
|
+
const message = lines.slice(1).join("\n").trim();
|
|
1639
|
+
const subject = message.split("\n")[0] || "";
|
|
1640
|
+
if (hash && REVERT_HOTFIX_RE.test(subject)) {
|
|
1641
|
+
entries.push({ hash, message });
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
return entries;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
/**
|
|
1648
|
+
* Get information about the runtime.
|
|
1649
|
+
*
|
|
1650
|
+
* @returns {Object} Object containing the name and version of the runtime
|
|
1651
|
+
*/
|
|
1652
|
+
export function getRuntimeInformation() {
|
|
1653
|
+
const runtimeInfo = {};
|
|
1654
|
+
if (isDeno) {
|
|
1655
|
+
runtimeInfo.runtime = "Deno";
|
|
1656
|
+
runtimeInfo.version = globalThis.Deno.version.deno;
|
|
1657
|
+
} else if (isBun) {
|
|
1658
|
+
runtimeInfo.runtime = "Bun";
|
|
1659
|
+
runtimeInfo.version = globalThis.Bun.version;
|
|
1660
|
+
} else if (isNode) {
|
|
1661
|
+
runtimeInfo.runtime = "Node.js";
|
|
1662
|
+
runtimeInfo.version = globalThis.process.versions.node;
|
|
1663
|
+
const report = process.report.getReport();
|
|
1664
|
+
const nodeSourceUrl = report?.header?.release?.sourceUrl;
|
|
1665
|
+
// Collect the bundled components in node.js
|
|
1666
|
+
if (report?.header?.componentVersions) {
|
|
1667
|
+
const nodeBundledComponents = [];
|
|
1668
|
+
for (const [name, version] of Object.entries(
|
|
1669
|
+
report.header.componentVersions,
|
|
1670
|
+
)) {
|
|
1671
|
+
if (name === "node") {
|
|
1672
|
+
continue;
|
|
1673
|
+
}
|
|
1674
|
+
const bundledPurl = tryBuildPurl({
|
|
1675
|
+
type: "generic",
|
|
1676
|
+
name,
|
|
1677
|
+
version: version || null,
|
|
1678
|
+
});
|
|
1679
|
+
const apkg = {
|
|
1680
|
+
name,
|
|
1681
|
+
version,
|
|
1682
|
+
description: `Bundled with Node.js ${runtimeInfo.version}`,
|
|
1683
|
+
type: "library",
|
|
1684
|
+
scope: "excluded",
|
|
1685
|
+
};
|
|
1686
|
+
applyPurl(apkg, bundledPurl);
|
|
1687
|
+
if (nodeSourceUrl) {
|
|
1688
|
+
apkg.externalReferences = [
|
|
1689
|
+
{
|
|
1690
|
+
url: nodeSourceUrl,
|
|
1691
|
+
type: "source-distribution",
|
|
1692
|
+
comment: "Node.js release url",
|
|
1693
|
+
},
|
|
1694
|
+
];
|
|
1695
|
+
}
|
|
1696
|
+
nodeBundledComponents.push(apkg);
|
|
1697
|
+
}
|
|
1698
|
+
if (nodeBundledComponents.length) {
|
|
1699
|
+
runtimeInfo.components = nodeBundledComponents;
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
if (report.sharedObjects) {
|
|
1703
|
+
const osSharedObjects = [];
|
|
1704
|
+
for (const aso of report.sharedObjects) {
|
|
1705
|
+
const name = basename(aso);
|
|
1706
|
+
if (name === "node") {
|
|
1707
|
+
continue;
|
|
1708
|
+
}
|
|
1709
|
+
const apkg = {
|
|
1710
|
+
name,
|
|
1711
|
+
type: "library",
|
|
1712
|
+
scope: "excluded",
|
|
1713
|
+
};
|
|
1714
|
+
// The absolute library path belongs in the purl subpath, which is
|
|
1715
|
+
// relative by definition — a leading slash makes the purl invalid, and
|
|
1716
|
+
// names like libstdc++.so.6 need percent-encoding. The path is also the
|
|
1717
|
+
// only thing distinguishing two libraries that share a basename, so it
|
|
1718
|
+
// has to reach the bom-ref too; `pkg:generic/${name}` collided.
|
|
1719
|
+
applyPurl(
|
|
1720
|
+
apkg,
|
|
1721
|
+
tryBuildPurl({
|
|
1722
|
+
type: "generic",
|
|
1723
|
+
name,
|
|
1724
|
+
subpath: aso ? String(aso).replace(/^\/+/, "") : null,
|
|
1725
|
+
}),
|
|
1726
|
+
);
|
|
1727
|
+
osSharedObjects.push(apkg);
|
|
1728
|
+
}
|
|
1729
|
+
if (osSharedObjects.length) {
|
|
1730
|
+
// Append rather than assign: the bundled-component list built above is
|
|
1731
|
+
// stored in the same property and was being silently discarded.
|
|
1732
|
+
runtimeInfo.components = [
|
|
1733
|
+
...(runtimeInfo.components ?? []),
|
|
1734
|
+
...osSharedObjects,
|
|
1735
|
+
];
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
} else {
|
|
1739
|
+
runtimeInfo.runtime = "Unknown";
|
|
1740
|
+
runtimeInfo.version = "N/A";
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
return runtimeInfo;
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
/**
|
|
1747
|
+
* Checks for dangerous Unicode characters that could enable homograph attacks
|
|
1748
|
+
if (zeroWidthChars.test(str)) {
|
|
1749
|
+
return true;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
// Check for control characters (except common ones like \n, \r, \t)
|
|
1753
|
+
const controlChars = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/;
|
|
1754
|
+
return controlChars.test(str);
|
|
1755
|
+
}
|
|
1756
|
+
// biome-ignore-end lint/suspicious/noControlCharactersInRegex: validation
|
|
1757
|
+
|
|
1758
|
+
/**
|
|
1759
|
+
* Get version and runtime information
|
|
1760
|
+
*/
|
|
1761
|
+
export function retrieveCdxgenVersion() {
|
|
1762
|
+
const packageJsonAsString = readFileSync(
|
|
1763
|
+
join(dirNameStr, "package.json"),
|
|
1764
|
+
"utf-8",
|
|
1765
|
+
);
|
|
1766
|
+
const packageJson = JSON.parse(packageJsonAsString);
|
|
1767
|
+
|
|
1768
|
+
const runtimeInfo = getRuntimeInformation();
|
|
1769
|
+
|
|
1770
|
+
return `\x1b[1mCycloneDX Generator ${packageJson.version}\x1b[0m\nRuntime: ${runtimeInfo.runtime}, Version: ${runtimeInfo.version}`;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
/**
|
|
1774
|
+
* Retrieve the version of the cdxgen plugins binary package from package.json.
|
|
1775
|
+
*
|
|
1776
|
+
* Reads the local package.json and searches the `optionalDependencies` for a package
|
|
1777
|
+
* whose name starts with `@cdxgen/cdxgen-plugins-bin`, returning its declared version.
|
|
1778
|
+
*
|
|
1779
|
+
* @returns {string|undefined} Version string of the plugins binary package, or undefined if not found
|
|
1780
|
+
*/
|
|
1781
|
+
export function retrieveCdxgenPluginVersion() {
|
|
1782
|
+
const packageJsonAsString = readFileSync(
|
|
1783
|
+
join(dirNameStr, "package.json"),
|
|
1784
|
+
"utf-8",
|
|
1785
|
+
);
|
|
1786
|
+
const packageJson = JSON.parse(packageJsonAsString);
|
|
1787
|
+
for (const adepName of Object.keys(packageJson.optionalDependencies || {})) {
|
|
1788
|
+
if (adepName.startsWith("@cdxgen/cdxgen-plugins-bin")) {
|
|
1789
|
+
return packageJson.optionalDependencies[adepName];
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
return undefined;
|
|
1793
|
+
}
|