@cdxgen/cdxgen 0.0.1 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +921 -87
- package/bin/audit.js +239 -0
- package/bin/cdxgen.js +2324 -0
- package/bin/convert.js +213 -0
- package/bin/evinse.js +353 -0
- package/bin/hbom.js +495 -0
- package/bin/repl.js +2224 -0
- package/bin/sign.js +195 -0
- package/bin/tracebom.js +295 -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 +1833 -0
- package/lib/cli/cliOptions.js +513 -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 +142 -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 +876 -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 +575 -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 +1789 -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 +277 -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 +263 -0
- package/lib/inventory/traceRunner.js +439 -0
- package/lib/inventory/unicodeScan.js +147 -0
- package/lib/managers/binary.js +3307 -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 +315 -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 +28 -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 +120 -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 +19 -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 +76 -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,2125 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
|
|
7
|
+
import { build } from "@cdxgen/cdx-purl";
|
|
8
|
+
import { parse as loadYaml } from "yaml";
|
|
9
|
+
|
|
10
|
+
import { DEBUG_MODE, readEnvironmentVariable } from "../core/activity.js";
|
|
11
|
+
import {
|
|
12
|
+
CARGO_CMD,
|
|
13
|
+
CLJ_CMD,
|
|
14
|
+
hasAnyProjectType,
|
|
15
|
+
LEIN_CMD,
|
|
16
|
+
SWIFT_CMD,
|
|
17
|
+
shouldFetchLicense,
|
|
18
|
+
} from "../core/env.js";
|
|
19
|
+
import {
|
|
20
|
+
checksumFile,
|
|
21
|
+
getAllFiles,
|
|
22
|
+
safeExistsSync,
|
|
23
|
+
safeSpawnSync,
|
|
24
|
+
} from "../core/fs.js";
|
|
25
|
+
import { thoughtLog } from "../core/logger.js";
|
|
26
|
+
import { dirNameStr, isMac } from "../core/paths.js";
|
|
27
|
+
import {
|
|
28
|
+
buildDependentPurl,
|
|
29
|
+
collapseCmakeVersions,
|
|
30
|
+
resolveCmakeContext,
|
|
31
|
+
} from "../ecosystems/cmakeResolver.js";
|
|
32
|
+
import { getCppModules } from "../ecosystems/cppEvidence.js";
|
|
33
|
+
import {
|
|
34
|
+
getCratesMetadata,
|
|
35
|
+
getSwiftPackageMetadata,
|
|
36
|
+
} from "../ecosystems/ecosystems.js";
|
|
37
|
+
import { parseGleamProject } from "../ecosystems/parsers-gleam.js";
|
|
38
|
+
import {
|
|
39
|
+
parseGoListDep,
|
|
40
|
+
parseGoModData,
|
|
41
|
+
parseGoModGraph,
|
|
42
|
+
parseGoModulesTxt,
|
|
43
|
+
parseGoModWhy,
|
|
44
|
+
parseGopkgData,
|
|
45
|
+
parseGosumData,
|
|
46
|
+
} from "../ecosystems/parsers-go.js";
|
|
47
|
+
import {
|
|
48
|
+
parseCljDep,
|
|
49
|
+
parseEdnData,
|
|
50
|
+
parseLeinDep,
|
|
51
|
+
parseLeiningenData,
|
|
52
|
+
} from "../ecosystems/parsers-jvm.js";
|
|
53
|
+
import {
|
|
54
|
+
buildObjectForCocoaPod,
|
|
55
|
+
executeAlpmList,
|
|
56
|
+
executeApkList,
|
|
57
|
+
executeDpkgList,
|
|
58
|
+
executeEqueryList,
|
|
59
|
+
executePodCommand,
|
|
60
|
+
executeRpmList,
|
|
61
|
+
parseCabalData,
|
|
62
|
+
parseCmakeLikeFile,
|
|
63
|
+
parseCocoaDependency,
|
|
64
|
+
parseColliderLockData,
|
|
65
|
+
parseConanData,
|
|
66
|
+
parseConanLockData,
|
|
67
|
+
parseFlakeLock,
|
|
68
|
+
parseFlakeNix,
|
|
69
|
+
parseMakeDFile,
|
|
70
|
+
parseMixLockData,
|
|
71
|
+
parsePodfileLock,
|
|
72
|
+
parsePodfileTargets,
|
|
73
|
+
parsePubLockData,
|
|
74
|
+
parsePubYamlData,
|
|
75
|
+
parseSwiftJsonTree,
|
|
76
|
+
parseSwiftResolved,
|
|
77
|
+
prefetchCocoaPodspecs,
|
|
78
|
+
} from "../ecosystems/parsers-misc.js";
|
|
79
|
+
import {
|
|
80
|
+
parseCargoData,
|
|
81
|
+
parseCargoDependencyData,
|
|
82
|
+
parseCargoManifestDependencyData,
|
|
83
|
+
parseCargoTomlData,
|
|
84
|
+
} from "../ecosystems/parsers-rust.js";
|
|
85
|
+
import { resolveZigGraph } from "../ecosystems/zigResolver.js";
|
|
86
|
+
import { mergeDependencies, trimComponents } from "../inventory/depsUtils.js";
|
|
87
|
+
import { convertOSQueryResults } from "../inventory/evidenceUtils.js";
|
|
88
|
+
import { applyPurl, nixBomRef, tryBuildPurl } from "../inventory/purl.js";
|
|
89
|
+
import { executeOsQuery } from "../managers/binary.js";
|
|
90
|
+
import {
|
|
91
|
+
buildBomNSData,
|
|
92
|
+
createBinaryBom,
|
|
93
|
+
createDefaultParentComponent,
|
|
94
|
+
} from "./bomAssembly.js";
|
|
95
|
+
|
|
96
|
+
const isWin = process.platform === "win32";
|
|
97
|
+
|
|
98
|
+
const cosDbQueries = JSON.parse(
|
|
99
|
+
readFileSync(join(dirNameStr, "data", "cosdb-queries.json"), "utf-8"),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Strip an unresolved CMake/MSBuild variable from a component's version and purl.
|
|
104
|
+
*
|
|
105
|
+
* A variable defined in a parent `CMakeLists.txt` (`project(foo VERSION
|
|
106
|
+
* ${PARENT_VERSION})`) cannot be resolved from the file that references it, and
|
|
107
|
+
* percent-encoding one into a purl publishes the variable name as the version
|
|
108
|
+
* (`pkg:generic/foo@%24%7B...%7D`). The scrapers drop such versions at the
|
|
109
|
+
* point they are read; this is the final check over everything reaching the
|
|
110
|
+
* BOM, covering components contributed by `cppEvidence` and the CMake cache
|
|
111
|
+
* resolver as well.
|
|
112
|
+
*
|
|
113
|
+
* @param {object} component Component to sanitise in place
|
|
114
|
+
*/
|
|
115
|
+
function sanitizeUnresolvedPurl(component) {
|
|
116
|
+
if (!component) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const hasUnresolvedVar =
|
|
120
|
+
component.version?.includes("${") ||
|
|
121
|
+
(component.purl &&
|
|
122
|
+
(component.purl.includes("%24%7B") || component.purl.includes("${")));
|
|
123
|
+
if (!hasUnresolvedVar) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (component.version?.includes("${")) {
|
|
127
|
+
component.version = "";
|
|
128
|
+
}
|
|
129
|
+
applyPurl(
|
|
130
|
+
component,
|
|
131
|
+
tryBuildPurl({
|
|
132
|
+
type: "generic",
|
|
133
|
+
namespace: component.group || null,
|
|
134
|
+
name: component.name,
|
|
135
|
+
version: null,
|
|
136
|
+
}),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Resolves the local Cargo registry cache directory from the `CARGO_CACHE_DIR`
|
|
142
|
+
* or `CARGO_HOME` environment variables, falling back to `~/.cargo/registry/cache`.
|
|
143
|
+
*
|
|
144
|
+
* @returns {string|undefined} Absolute path to the Cargo cache directory
|
|
145
|
+
*/
|
|
146
|
+
export function getCargoCacheDir() {
|
|
147
|
+
return readEnvironmentVariable("CARGO_CACHE_DIR")
|
|
148
|
+
? resolve(readEnvironmentVariable("CARGO_CACHE_DIR"))
|
|
149
|
+
: resolve(
|
|
150
|
+
readEnvironmentVariable("CARGO_HOME") || join(homedir(), ".cargo"),
|
|
151
|
+
"registry",
|
|
152
|
+
"cache",
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Function to create bom string for Go projects
|
|
158
|
+
*
|
|
159
|
+
* @param {string} path to the project
|
|
160
|
+
* @param {Object} options Parse options from the cli
|
|
161
|
+
* @returns {Promise<Object | undefined>} Promise resolving to a BOM object or `undefined`
|
|
162
|
+
*/
|
|
163
|
+
export async function createGoBom(path, options) {
|
|
164
|
+
let pkgList = [];
|
|
165
|
+
let dependencies = [];
|
|
166
|
+
const allImports = {};
|
|
167
|
+
let parentComponent = createDefaultParentComponent(path, "golang", options);
|
|
168
|
+
// Is this a binary file
|
|
169
|
+
let maybeBinary;
|
|
170
|
+
try {
|
|
171
|
+
maybeBinary = statSync(path).isFile();
|
|
172
|
+
} catch (_err) {
|
|
173
|
+
maybeBinary = false;
|
|
174
|
+
}
|
|
175
|
+
if (maybeBinary || options?.lifecycle?.includes("post-build")) {
|
|
176
|
+
return createBinaryBom(path, options);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Read in go.sum and merge all go.sum files.
|
|
180
|
+
const gosumFiles = getAllFiles(
|
|
181
|
+
path,
|
|
182
|
+
`${options.multiProject ? "**/" : ""}go.sum`,
|
|
183
|
+
options,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// If USE_GOSUM is true|1, generate BOM components only using go.sum.
|
|
187
|
+
const useGosum =
|
|
188
|
+
readEnvironmentVariable("USE_GOSUM") &&
|
|
189
|
+
["true", "1"].includes(readEnvironmentVariable("USE_GOSUM"));
|
|
190
|
+
if (useGosum && gosumFiles.length) {
|
|
191
|
+
console.warn(
|
|
192
|
+
"Using go.sum to generate BOMs for go projects may return an inaccurate representation of transitive dependencies.\nSee: https://github.com/golang/go/wiki/Modules#is-gosum-a-lock-file-why-does-gosum-include-information-for-module-versions-i-am-no-longer-using\n",
|
|
193
|
+
"Set USE_GOSUM=false to generate BOMs using go.mod as the dependency source of truth.",
|
|
194
|
+
);
|
|
195
|
+
for (const f of gosumFiles) {
|
|
196
|
+
if (DEBUG_MODE) {
|
|
197
|
+
console.log(`Parsing ${f}`);
|
|
198
|
+
}
|
|
199
|
+
const gosumData = readFileSync(f, { encoding: "utf-8" });
|
|
200
|
+
const dlist = await parseGosumData(gosumData);
|
|
201
|
+
if (dlist?.length) {
|
|
202
|
+
pkgList = pkgList.concat(dlist);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const doneList = {};
|
|
206
|
+
let circuitBreak = false;
|
|
207
|
+
if (DEBUG_MODE) {
|
|
208
|
+
console.log(
|
|
209
|
+
`Attempting to detect required packages using "go mod why" command for ${pkgList.length} packages`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
// Using go mod why detect required packages
|
|
213
|
+
for (const apkg of pkgList) {
|
|
214
|
+
if (circuitBreak) {
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
const pkgFullName = `${apkg.name}`;
|
|
218
|
+
if (apkg.scope === "required") {
|
|
219
|
+
allImports[pkgFullName] = true;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (
|
|
223
|
+
apkg.scope === "optional" ||
|
|
224
|
+
allImports[pkgFullName] ||
|
|
225
|
+
doneList[pkgFullName]
|
|
226
|
+
) {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (DEBUG_MODE) {
|
|
230
|
+
console.log(`go mod why -m -vendor ${pkgFullName}`);
|
|
231
|
+
}
|
|
232
|
+
const mresult = safeSpawnSync(
|
|
233
|
+
"go",
|
|
234
|
+
["mod", "why", "-m", "-vendor", pkgFullName],
|
|
235
|
+
{
|
|
236
|
+
cwd: path,
|
|
237
|
+
},
|
|
238
|
+
);
|
|
239
|
+
if (mresult.status !== 0 || mresult.error) {
|
|
240
|
+
if (DEBUG_MODE) {
|
|
241
|
+
if (mresult.stdout) {
|
|
242
|
+
console.log(mresult.stdout);
|
|
243
|
+
}
|
|
244
|
+
if (mresult.stderr) {
|
|
245
|
+
console.log(mresult.stderr);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
circuitBreak = true;
|
|
249
|
+
} else {
|
|
250
|
+
const mstdout = mresult.stdout;
|
|
251
|
+
if (mstdout) {
|
|
252
|
+
const cmdOutput = Buffer.from(mstdout).toString();
|
|
253
|
+
const whyPkg = parseGoModWhy(cmdOutput);
|
|
254
|
+
// whyPkg would include this package string
|
|
255
|
+
// github.com/golang/protobuf/proto github.com/golang/protobuf
|
|
256
|
+
// golang.org/x/tools/cmd/goimports golang.org/x/tools
|
|
257
|
+
if (whyPkg?.includes(pkgFullName)) {
|
|
258
|
+
allImports[pkgFullName] = true;
|
|
259
|
+
}
|
|
260
|
+
doneList[pkgFullName] = true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (DEBUG_MODE) {
|
|
265
|
+
console.log(`Required packages: ${Object.keys(allImports).length}`);
|
|
266
|
+
}
|
|
267
|
+
return buildBomNSData(options, pkgList, "golang", {
|
|
268
|
+
src: path,
|
|
269
|
+
dependencies,
|
|
270
|
+
parentComponent,
|
|
271
|
+
filename: gosumFiles.join(", "),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// If USE_GOSUM is false, generate BOM components using go.mod.
|
|
276
|
+
const gosumMap = {};
|
|
277
|
+
if (gosumFiles.length) {
|
|
278
|
+
for (const f of gosumFiles) {
|
|
279
|
+
if (DEBUG_MODE) {
|
|
280
|
+
console.log(`Parsing ${f}`);
|
|
281
|
+
}
|
|
282
|
+
const gosumData = readFileSync(f, { encoding: "utf-8" });
|
|
283
|
+
const dlist = await parseGosumData(gosumData);
|
|
284
|
+
if (dlist?.length) {
|
|
285
|
+
dlist.forEach((pkg) => {
|
|
286
|
+
gosumMap[`${pkg.name}@${pkg.version}`] = pkg._integrity;
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Read in data from Gopkg.lock files if they exist
|
|
293
|
+
const gopkgLockFiles = getAllFiles(
|
|
294
|
+
path,
|
|
295
|
+
`${options.multiProject ? "**/" : ""}Gopkg.lock`,
|
|
296
|
+
options,
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
// Read in go.mod files and parse BOM components with checksums from gosumData
|
|
300
|
+
const gomodFiles = getAllFiles(
|
|
301
|
+
path,
|
|
302
|
+
`${options.multiProject ? "**/" : ""}go.mod`,
|
|
303
|
+
options,
|
|
304
|
+
);
|
|
305
|
+
// Collect any vendored dependencies
|
|
306
|
+
const modulesTxtFiles = getAllFiles(path, "vendor/**/modules.txt", options);
|
|
307
|
+
for (const f of modulesTxtFiles) {
|
|
308
|
+
const dlist = await parseGoModulesTxt(f, gosumMap);
|
|
309
|
+
pkgList = pkgList.concat(dlist);
|
|
310
|
+
}
|
|
311
|
+
if (gomodFiles.length) {
|
|
312
|
+
let shouldManuallyParse = false;
|
|
313
|
+
// Sort go.mod files by depth (shallowest first) to prioritize root modules
|
|
314
|
+
const sortedGomodFiles = gomodFiles.sort((a, b) => {
|
|
315
|
+
const relativePathA = relative(path, a);
|
|
316
|
+
const relativePathB = relative(path, b);
|
|
317
|
+
const depthA = relativePathA.split("/").length;
|
|
318
|
+
const depthB = relativePathB.split("/").length;
|
|
319
|
+
return depthA - depthB;
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
let rootParentComponent = null;
|
|
323
|
+
// Use the go list -deps and go mod why commands to generate a good quality BOM for non-docker invocations
|
|
324
|
+
if (
|
|
325
|
+
!hasAnyProjectType(["docker", "oci", "container", "os"], options, false)
|
|
326
|
+
) {
|
|
327
|
+
for (const f of sortedGomodFiles) {
|
|
328
|
+
const basePath = dirname(f);
|
|
329
|
+
// Ignore vendor packages and test fixtures
|
|
330
|
+
if (
|
|
331
|
+
basePath.includes("/vendor/") ||
|
|
332
|
+
basePath.includes("/build/") ||
|
|
333
|
+
basePath.includes("/test-fixtures/")
|
|
334
|
+
) {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
// First we execute the go list -deps command which gives the correct list of dependencies
|
|
338
|
+
if (DEBUG_MODE) {
|
|
339
|
+
console.log("Executing go list -deps in", basePath);
|
|
340
|
+
}
|
|
341
|
+
// TODO: Replacing this with -json gives us more interesting data points such as GoFiles, Imports, and Deps
|
|
342
|
+
let result = safeSpawnSync(
|
|
343
|
+
"go",
|
|
344
|
+
[
|
|
345
|
+
"list",
|
|
346
|
+
"-deps",
|
|
347
|
+
"-f",
|
|
348
|
+
"'{{with .Module}}{{.Path}}|{{.Version}}|{{.Indirect}}|{{.GoMod}}|{{.GoVersion}}|{{.Main}}|{{.Time}}|{{.Deprecated}}|{{.GoModSum}}|{{.Dir}}{{end}}'",
|
|
349
|
+
"./...",
|
|
350
|
+
],
|
|
351
|
+
{
|
|
352
|
+
cwd: basePath,
|
|
353
|
+
},
|
|
354
|
+
);
|
|
355
|
+
if (result.status !== 0 || result.error) {
|
|
356
|
+
// go list -deps command may not work when private packages are involved
|
|
357
|
+
// So we support a fallback to only operate with go mod graph command output in such instances
|
|
358
|
+
console.log("go list -deps command has failed for", basePath);
|
|
359
|
+
shouldManuallyParse = true;
|
|
360
|
+
if (DEBUG_MODE && result.stdout) {
|
|
361
|
+
console.log(result.stdout);
|
|
362
|
+
}
|
|
363
|
+
if (DEBUG_MODE && result.stderr) {
|
|
364
|
+
console.log(result.stderr);
|
|
365
|
+
}
|
|
366
|
+
options.failOnError && process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
const stdout = result.stdout;
|
|
369
|
+
if (stdout) {
|
|
370
|
+
let cmdOutput = Buffer.from(stdout).toString();
|
|
371
|
+
const retMap = await parseGoListDep(cmdOutput, gosumMap);
|
|
372
|
+
if (retMap.pkgList?.length) {
|
|
373
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
374
|
+
}
|
|
375
|
+
// Prioritize the shallowest module as the root component
|
|
376
|
+
if (
|
|
377
|
+
retMap.parentComponent &&
|
|
378
|
+
Object.keys(retMap.parentComponent).length
|
|
379
|
+
) {
|
|
380
|
+
if (!rootParentComponent) {
|
|
381
|
+
// First (shallowest) module becomes the root
|
|
382
|
+
rootParentComponent = retMap.parentComponent;
|
|
383
|
+
rootParentComponent.type = "application";
|
|
384
|
+
parentComponent = rootParentComponent;
|
|
385
|
+
} else {
|
|
386
|
+
// Subsequent modules become subcomponents
|
|
387
|
+
if (!parentComponent.components) {
|
|
388
|
+
parentComponent.components = [];
|
|
389
|
+
}
|
|
390
|
+
parentComponent.components.push(retMap.parentComponent);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (DEBUG_MODE) {
|
|
394
|
+
console.log("Executing go mod graph in", basePath);
|
|
395
|
+
}
|
|
396
|
+
// Next we use the go mod graph command to construct the dependency tree
|
|
397
|
+
result = safeSpawnSync("go", ["mod", "graph"], {
|
|
398
|
+
cwd: basePath,
|
|
399
|
+
});
|
|
400
|
+
// Check if got a mod graph successfully
|
|
401
|
+
if (result.status !== 0 || result.error) {
|
|
402
|
+
console.log("go mod graph command has failed.");
|
|
403
|
+
if (DEBUG_MODE && result.stdout) {
|
|
404
|
+
console.log(result.stdout);
|
|
405
|
+
if (result?.stdout.includes("unrecognized import path")) {
|
|
406
|
+
console.log(
|
|
407
|
+
"go couldn't download all the modules, including any private modules. Dependency tree would be missing.",
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (DEBUG_MODE && result.stderr) {
|
|
412
|
+
console.log(result.stderr);
|
|
413
|
+
}
|
|
414
|
+
options.failOnError && process.exit(1);
|
|
415
|
+
}
|
|
416
|
+
if (result.stdout) {
|
|
417
|
+
cmdOutput = Buffer.from(result.stdout).toString();
|
|
418
|
+
const retMap = await parseGoModGraph(
|
|
419
|
+
cmdOutput,
|
|
420
|
+
f,
|
|
421
|
+
gosumMap,
|
|
422
|
+
pkgList,
|
|
423
|
+
parentComponent,
|
|
424
|
+
);
|
|
425
|
+
if (retMap.pkgList?.length) {
|
|
426
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
427
|
+
pkgList = trimComponents(pkgList);
|
|
428
|
+
}
|
|
429
|
+
if (retMap.dependenciesList?.length) {
|
|
430
|
+
dependencies = mergeDependencies(
|
|
431
|
+
dependencies,
|
|
432
|
+
retMap.dependenciesList,
|
|
433
|
+
parentComponent,
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
// Retain the parent component hierarchy
|
|
437
|
+
if (Object.keys(retMap.parentComponent).length) {
|
|
438
|
+
parentComponent.components = parentComponent.components || [];
|
|
439
|
+
parentComponent.components.push(retMap.parentComponent);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
} else {
|
|
443
|
+
if (DEBUG_MODE) {
|
|
444
|
+
console.log("Executing go mod graph in", basePath);
|
|
445
|
+
}
|
|
446
|
+
// Next we use the go mod graph command to construct the dependency tree
|
|
447
|
+
result = safeSpawnSync("go", ["mod", "graph"], {
|
|
448
|
+
cwd: basePath,
|
|
449
|
+
shell: isWin,
|
|
450
|
+
});
|
|
451
|
+
if (result.stdout) {
|
|
452
|
+
const cmdOutput = Buffer.from(result.stdout).toString();
|
|
453
|
+
// The arguments to parseGoModGraph are slightly different to force inclusion of all packages
|
|
454
|
+
const retMap = await parseGoModGraph(
|
|
455
|
+
cmdOutput,
|
|
456
|
+
f,
|
|
457
|
+
gosumMap,
|
|
458
|
+
[],
|
|
459
|
+
{},
|
|
460
|
+
);
|
|
461
|
+
if (retMap.pkgList?.length) {
|
|
462
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
463
|
+
pkgList = trimComponents(pkgList);
|
|
464
|
+
}
|
|
465
|
+
if (retMap.dependenciesList?.length) {
|
|
466
|
+
dependencies = mergeDependencies(
|
|
467
|
+
dependencies,
|
|
468
|
+
retMap.dependenciesList,
|
|
469
|
+
parentComponent,
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
// Retain the parent component hierarchy, prioritizing the shallowest module
|
|
473
|
+
if (Object.keys(retMap.parentComponent).length) {
|
|
474
|
+
if (!rootParentComponent) {
|
|
475
|
+
// First (shallowest) module becomes the root
|
|
476
|
+
rootParentComponent = retMap.parentComponent;
|
|
477
|
+
parentComponent = rootParentComponent;
|
|
478
|
+
} else {
|
|
479
|
+
// Subsequent modules become subcomponents
|
|
480
|
+
parentComponent.components = parentComponent.components || [];
|
|
481
|
+
parentComponent.components.push(retMap.parentComponent);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
} else {
|
|
485
|
+
shouldManuallyParse = true;
|
|
486
|
+
console.log(
|
|
487
|
+
"1. Check if the correct version of golang is installed. Try building the application using go build or make command to troubleshoot.",
|
|
488
|
+
);
|
|
489
|
+
console.log(
|
|
490
|
+
"2. If the application uses private go modules, ensure the environment variable GOPRIVATE is set with the comma-separated repo names.\nEnsure $HOME/.netrc file contains a valid username and password for the private repos.",
|
|
491
|
+
);
|
|
492
|
+
console.log(
|
|
493
|
+
"3. Alternatively, consider generating a post-build SBOM from the built binary using blint. Use the official container image and invoke cdxgen with the arguments `-t binary --lifecycle post-build`.",
|
|
494
|
+
);
|
|
495
|
+
options.failOnError && process.exit(1);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (pkgList.length && !shouldManuallyParse) {
|
|
500
|
+
return buildBomNSData(options, pkgList, "golang", {
|
|
501
|
+
allImports,
|
|
502
|
+
dependencies,
|
|
503
|
+
parentComponent,
|
|
504
|
+
src: path,
|
|
505
|
+
filename: sortedGomodFiles.join(", "),
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
// Parse the gomod files manually. The resultant BOM would be incomplete
|
|
510
|
+
if (
|
|
511
|
+
!hasAnyProjectType(["docker", "oci", "container", "os"], options, false)
|
|
512
|
+
) {
|
|
513
|
+
console.log(
|
|
514
|
+
"Manually parsing go.mod files. The resultant BOM would be incomplete.",
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
for (const f of sortedGomodFiles) {
|
|
518
|
+
if (DEBUG_MODE) {
|
|
519
|
+
console.log(`Parsing ${f}`);
|
|
520
|
+
}
|
|
521
|
+
const gomodData = readFileSync(f, { encoding: "utf-8" });
|
|
522
|
+
const retMap = await parseGoModData(gomodData, gosumMap);
|
|
523
|
+
if (retMap?.pkgList?.length) {
|
|
524
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
525
|
+
}
|
|
526
|
+
// Retain the parent component hierarchy, prioritizing the shallowest module
|
|
527
|
+
if (
|
|
528
|
+
retMap?.parentComponent &&
|
|
529
|
+
Object.keys(retMap.parentComponent).length
|
|
530
|
+
) {
|
|
531
|
+
if (!rootParentComponent) {
|
|
532
|
+
// First (shallowest) module becomes the root
|
|
533
|
+
rootParentComponent = retMap.parentComponent;
|
|
534
|
+
parentComponent = rootParentComponent;
|
|
535
|
+
} else {
|
|
536
|
+
// Subsequent modules become subcomponents
|
|
537
|
+
parentComponent.components = parentComponent.components || [];
|
|
538
|
+
parentComponent.components.push(retMap.parentComponent);
|
|
539
|
+
}
|
|
540
|
+
if (retMap?.rootList?.length) {
|
|
541
|
+
const thisParentDependsOn = [
|
|
542
|
+
{
|
|
543
|
+
ref: retMap.parentComponent["bom-ref"],
|
|
544
|
+
dependsOn: [
|
|
545
|
+
...new Set(retMap.rootList.map((c) => c["bom-ref"])),
|
|
546
|
+
].sort(),
|
|
547
|
+
},
|
|
548
|
+
];
|
|
549
|
+
dependencies = mergeDependencies(
|
|
550
|
+
dependencies,
|
|
551
|
+
thisParentDependsOn,
|
|
552
|
+
parentComponent,
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return buildBomNSData(options, pkgList, "golang", {
|
|
558
|
+
src: path,
|
|
559
|
+
dependencies,
|
|
560
|
+
parentComponent,
|
|
561
|
+
filename: sortedGomodFiles.join(", "),
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
if (gopkgLockFiles.length) {
|
|
565
|
+
for (const f of gopkgLockFiles) {
|
|
566
|
+
if (DEBUG_MODE) {
|
|
567
|
+
console.log(`Parsing ${f}`);
|
|
568
|
+
}
|
|
569
|
+
const gopkgData = readFileSync(f, {
|
|
570
|
+
encoding: "utf-8",
|
|
571
|
+
});
|
|
572
|
+
const dlist = await parseGopkgData(gopkgData);
|
|
573
|
+
if (dlist?.length) {
|
|
574
|
+
pkgList = pkgList.concat(dlist);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return buildBomNSData(options, pkgList, "golang", {
|
|
578
|
+
src: path,
|
|
579
|
+
dependencies,
|
|
580
|
+
parentComponent,
|
|
581
|
+
filename: gopkgLockFiles.join(", "),
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
return {};
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Function to create bom string for Rust projects
|
|
589
|
+
*
|
|
590
|
+
* @param {string} path to the project
|
|
591
|
+
* @param {Object} options Parse options from the cli
|
|
592
|
+
* @returns {Promise<Object|undefined>} Promise resolving to a BOM object or undefined
|
|
593
|
+
*/
|
|
594
|
+
export async function createRustBom(path, options) {
|
|
595
|
+
let pkgList = [];
|
|
596
|
+
let parentComponent = {};
|
|
597
|
+
// Is this a binary file
|
|
598
|
+
let maybeBinary;
|
|
599
|
+
try {
|
|
600
|
+
maybeBinary = statSync(path).isFile();
|
|
601
|
+
} catch (_err) {
|
|
602
|
+
maybeBinary = false;
|
|
603
|
+
}
|
|
604
|
+
if (maybeBinary || options?.lifecycle?.includes("post-build")) {
|
|
605
|
+
return createBinaryBom(path, options);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// This function assumes that the given path is prioritized, i.e that the
|
|
609
|
+
// Cargo.toml-file directly inside the directory `path` (or the one in the
|
|
610
|
+
// shortest distance from the `path` directory) will be the first returned
|
|
611
|
+
// object. If that assumption is broken, the parent component may be
|
|
612
|
+
// inaccurate.
|
|
613
|
+
const cargoFiles = getAllFiles(
|
|
614
|
+
path,
|
|
615
|
+
`${options.multiProject ? "**/" : ""}Cargo.toml`,
|
|
616
|
+
options,
|
|
617
|
+
);
|
|
618
|
+
// Attempt to build or generate lock files automatically
|
|
619
|
+
for (const f of cargoFiles) {
|
|
620
|
+
// If there are no cargo.lock files, we can attempt a cargo install when
|
|
621
|
+
// options.deep is true or options.lifecycle == build or post-build with installDeps
|
|
622
|
+
// Why the need for installDeps? It currently defaults to true, so let's obey if someone wants no installs
|
|
623
|
+
if (
|
|
624
|
+
(options.deep && !hasAnyProjectType(["oci"], options, false)) ||
|
|
625
|
+
(options.installDeps &&
|
|
626
|
+
!safeExistsSync(f.replace(".toml", ".lock")) &&
|
|
627
|
+
["build", "post-build"].includes(options.lifecycle))
|
|
628
|
+
) {
|
|
629
|
+
const basePath = dirname(f);
|
|
630
|
+
const cargoArgs = options.deep
|
|
631
|
+
? ["check", "--all-features", "--manifest-path", f]
|
|
632
|
+
: ["generate-lockfile", "--manifest-path", f];
|
|
633
|
+
if (!DEBUG_MODE) {
|
|
634
|
+
cargoArgs.push("--quiet");
|
|
635
|
+
}
|
|
636
|
+
if (DEBUG_MODE) {
|
|
637
|
+
console.log(
|
|
638
|
+
"Executing ",
|
|
639
|
+
CARGO_CMD,
|
|
640
|
+
cargoArgs.join(" "),
|
|
641
|
+
"in",
|
|
642
|
+
basePath,
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
const cargoInstallResult = safeSpawnSync(CARGO_CMD, cargoArgs, {
|
|
646
|
+
cwd: basePath,
|
|
647
|
+
shell: isWin,
|
|
648
|
+
});
|
|
649
|
+
if (cargoInstallResult.status !== 0 || cargoInstallResult.error) {
|
|
650
|
+
console.error("Error running the cargo command");
|
|
651
|
+
console.log(cargoInstallResult.error, cargoInstallResult.stderr);
|
|
652
|
+
options.failOnError && process.exit(1);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
// After running cargo check, .d files would get created
|
|
657
|
+
let pkgFilesMap = {};
|
|
658
|
+
if (options.deep || ["build", "post-build"].includes(options.lifecycle)) {
|
|
659
|
+
const makeDFiles = getAllFiles(path, "target/**/*.d", options);
|
|
660
|
+
for (const dfile of makeDFiles) {
|
|
661
|
+
pkgFilesMap = { ...pkgFilesMap, ...parseMakeDFile(dfile) };
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
const cargoLockFiles = getAllFiles(
|
|
665
|
+
path,
|
|
666
|
+
`${options.multiProject ? "**/" : ""}Cargo.lock`,
|
|
667
|
+
options,
|
|
668
|
+
);
|
|
669
|
+
const cargoLockMode = cargoLockFiles.length;
|
|
670
|
+
for (const f of cargoFiles) {
|
|
671
|
+
if (DEBUG_MODE) {
|
|
672
|
+
console.log(`Parsing ${f}`);
|
|
673
|
+
}
|
|
674
|
+
const dlist = await parseCargoTomlData(f, cargoLockMode, pkgFilesMap, {
|
|
675
|
+
includeWorkspaceMembers: !options.multiProject,
|
|
676
|
+
});
|
|
677
|
+
if (dlist?.length) {
|
|
678
|
+
if (!cargoLockMode) {
|
|
679
|
+
pkgList = pkgList.concat(dlist);
|
|
680
|
+
} else {
|
|
681
|
+
if (!Object.keys(parentComponent).length) {
|
|
682
|
+
parentComponent = dlist[0];
|
|
683
|
+
parentComponent.type = "application";
|
|
684
|
+
parentComponent.components = [];
|
|
685
|
+
if (DEBUG_MODE) {
|
|
686
|
+
console.log(
|
|
687
|
+
`Assigning parent component "${parentComponent.name}" from ${f}`,
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
} else {
|
|
691
|
+
parentComponent.components.push(dlist[0]);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
let dependencyTree = [];
|
|
697
|
+
if (cargoLockMode) {
|
|
698
|
+
for (const f of cargoLockFiles) {
|
|
699
|
+
if (DEBUG_MODE) {
|
|
700
|
+
console.log(`Parsing ${f}`);
|
|
701
|
+
}
|
|
702
|
+
const dlist = await parseCargoData(f, false, pkgFilesMap);
|
|
703
|
+
if (dlist?.length) {
|
|
704
|
+
pkgList = pkgList.concat(dlist);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if (DEBUG_MODE) {
|
|
708
|
+
console.log(`Constructing dependency tree from ${f}`);
|
|
709
|
+
}
|
|
710
|
+
const cargoLockData = readFileSync(f, { encoding: "utf-8" });
|
|
711
|
+
const fileDependencylist = parseCargoDependencyData(cargoLockData);
|
|
712
|
+
if (fileDependencylist?.length) {
|
|
713
|
+
dependencyTree = mergeDependencies(
|
|
714
|
+
dependencyTree,
|
|
715
|
+
fileDependencylist,
|
|
716
|
+
parentComponent,
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
for (const f of cargoFiles) {
|
|
722
|
+
const manifestDependencyList = parseCargoManifestDependencyData(f, {
|
|
723
|
+
includeWorkspaceMembers: !options.multiProject,
|
|
724
|
+
});
|
|
725
|
+
if (manifestDependencyList?.length) {
|
|
726
|
+
dependencyTree = mergeDependencies(
|
|
727
|
+
dependencyTree,
|
|
728
|
+
manifestDependencyList,
|
|
729
|
+
parentComponent,
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return buildBomNSData(options, pkgList, "cargo", {
|
|
734
|
+
src: path,
|
|
735
|
+
filename: cargoLockFiles.join(", "),
|
|
736
|
+
dependencies: dependencyTree,
|
|
737
|
+
parentComponent,
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Parses a `.crate` file name into a CycloneDX component (name, version, purl,
|
|
743
|
+
* bom-ref, and source/cache properties). Returns undefined when the file name
|
|
744
|
+
* does not match the `name-version` convention.
|
|
745
|
+
*
|
|
746
|
+
* @param {string} crateFile Absolute path to a `.crate` archive
|
|
747
|
+
* @returns {object|undefined} Component object or undefined
|
|
748
|
+
*/
|
|
749
|
+
export function buildCargoCacheComponent(crateFile) {
|
|
750
|
+
const crateFileName = basename(crateFile, ".crate");
|
|
751
|
+
const nameVersionMatch = crateFileName.match(/^(.+)-([0-9][A-Za-z0-9.+-]*)$/);
|
|
752
|
+
if (!nameVersionMatch) {
|
|
753
|
+
return undefined;
|
|
754
|
+
}
|
|
755
|
+
const [, name, version] = nameVersionMatch;
|
|
756
|
+
const purl = build({
|
|
757
|
+
type: "cargo",
|
|
758
|
+
namespace: "" || null,
|
|
759
|
+
name: name,
|
|
760
|
+
version: version || null,
|
|
761
|
+
});
|
|
762
|
+
return {
|
|
763
|
+
"bom-ref": decodeURIComponent(purl),
|
|
764
|
+
group: "",
|
|
765
|
+
name,
|
|
766
|
+
properties: [
|
|
767
|
+
{
|
|
768
|
+
name: "internal:SrcFile",
|
|
769
|
+
value: crateFile,
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
name: "cdx:cargo:cacheSource",
|
|
773
|
+
value: "registry-cache",
|
|
774
|
+
},
|
|
775
|
+
],
|
|
776
|
+
purl,
|
|
777
|
+
type: "library",
|
|
778
|
+
version,
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Enriches a cargo cache component with a SHA-256 hash and filename-based
|
|
784
|
+
* identity evidence (confidence 0.5). Hash computation failures are ignored.
|
|
785
|
+
*
|
|
786
|
+
* @param {string} crateFile Absolute path to the `.crate` archive
|
|
787
|
+
* @param {object} [component] Component produced by `buildCargoCacheComponent`
|
|
788
|
+
* @returns {Promise<object|undefined>} The enriched component or undefined
|
|
789
|
+
*/
|
|
790
|
+
export async function enrichCargoCacheComponent(crateFile, component) {
|
|
791
|
+
if (!component) {
|
|
792
|
+
return undefined;
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
component.hashes = [
|
|
796
|
+
{
|
|
797
|
+
alg: "SHA-256",
|
|
798
|
+
content: await checksumFile("sha256", crateFile),
|
|
799
|
+
},
|
|
800
|
+
];
|
|
801
|
+
} catch {
|
|
802
|
+
// continue without hashes
|
|
803
|
+
}
|
|
804
|
+
component.evidence = {
|
|
805
|
+
identity: {
|
|
806
|
+
field: "purl",
|
|
807
|
+
confidence: 0.5,
|
|
808
|
+
methods: [
|
|
809
|
+
{
|
|
810
|
+
technique: "filename",
|
|
811
|
+
confidence: 0.5,
|
|
812
|
+
value: crateFile,
|
|
813
|
+
},
|
|
814
|
+
],
|
|
815
|
+
},
|
|
816
|
+
};
|
|
817
|
+
return component;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Builds a BOM from `.crate` files found in the Cargo registry cache (or from a
|
|
822
|
+
* single `.crate` path). Optionally fetches crates.io license metadata when
|
|
823
|
+
* license fetching is enabled.
|
|
824
|
+
*
|
|
825
|
+
* @param {string} path Directory or `.crate` file path
|
|
826
|
+
* @param {object} options CLI options
|
|
827
|
+
* @returns {Promise<object>} Promise resolving to a BOM namespace data object
|
|
828
|
+
*/
|
|
829
|
+
export async function createCargoCacheBom(path, options) {
|
|
830
|
+
const parentComponent = createDefaultParentComponent(path, "cargo", options);
|
|
831
|
+
const crateFiles = path.endsWith(".crate")
|
|
832
|
+
? [resolve(path)]
|
|
833
|
+
: getAllFiles(path, "**/*.crate", options);
|
|
834
|
+
let pkgList = [];
|
|
835
|
+
for (const crateFile of crateFiles) {
|
|
836
|
+
const component = await enrichCargoCacheComponent(
|
|
837
|
+
crateFile,
|
|
838
|
+
buildCargoCacheComponent(crateFile),
|
|
839
|
+
);
|
|
840
|
+
if (component) {
|
|
841
|
+
pkgList.push(component);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (pkgList.length && shouldFetchLicense()) {
|
|
845
|
+
pkgList = await getCratesMetadata(pkgList);
|
|
846
|
+
}
|
|
847
|
+
return buildBomNSData(options, pkgList, "cargo", {
|
|
848
|
+
src: path,
|
|
849
|
+
parentComponent,
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Function to create bom string for Dart projects
|
|
855
|
+
*
|
|
856
|
+
* @param {string} path to the project
|
|
857
|
+
* @param {Object} options Parse options from the cli
|
|
858
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
859
|
+
*/
|
|
860
|
+
export async function createDartBom(path, options) {
|
|
861
|
+
const pubFiles = getAllFiles(
|
|
862
|
+
path,
|
|
863
|
+
`${options.multiProject ? "**/" : ""}pubspec.lock`,
|
|
864
|
+
options,
|
|
865
|
+
);
|
|
866
|
+
const pubSpecYamlFiles = getAllFiles(
|
|
867
|
+
path,
|
|
868
|
+
`${options.multiProject ? "**/" : ""}pubspec.yaml`,
|
|
869
|
+
options,
|
|
870
|
+
);
|
|
871
|
+
let dependencies = [];
|
|
872
|
+
let pkgList = [];
|
|
873
|
+
let parentComponent;
|
|
874
|
+
if (pubSpecYamlFiles.length) {
|
|
875
|
+
for (const f of pubSpecYamlFiles) {
|
|
876
|
+
if (DEBUG_MODE) {
|
|
877
|
+
console.log(`Parsing ${f}`);
|
|
878
|
+
}
|
|
879
|
+
const pubYamlData = readFileSync(f, { encoding: "utf-8" });
|
|
880
|
+
const dlist = parsePubYamlData(pubYamlData);
|
|
881
|
+
if (dlist?.length) {
|
|
882
|
+
pkgList = pkgList.concat(dlist);
|
|
883
|
+
if (!parentComponent) {
|
|
884
|
+
parentComponent = pkgList[0];
|
|
885
|
+
parentComponent.type = "application";
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
if (pubFiles.length) {
|
|
891
|
+
for (const f of pubFiles) {
|
|
892
|
+
if (DEBUG_MODE) {
|
|
893
|
+
console.log(`Parsing ${f}`);
|
|
894
|
+
}
|
|
895
|
+
const pubLockData = readFileSync(f, { encoding: "utf-8" });
|
|
896
|
+
const retMap = await parsePubLockData(pubLockData, f);
|
|
897
|
+
if (retMap.pkgList?.length) {
|
|
898
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
899
|
+
}
|
|
900
|
+
if (retMap?.rootList?.length) {
|
|
901
|
+
const thisParentDependsOn = [
|
|
902
|
+
{
|
|
903
|
+
ref: parentComponent["bom-ref"],
|
|
904
|
+
dependsOn: [
|
|
905
|
+
...new Set(retMap.rootList.map((c) => c["bom-ref"])),
|
|
906
|
+
].sort(),
|
|
907
|
+
},
|
|
908
|
+
];
|
|
909
|
+
dependencies = mergeDependencies(
|
|
910
|
+
dependencies,
|
|
911
|
+
thisParentDependsOn,
|
|
912
|
+
parentComponent,
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
return buildBomNSData(options, pkgList, "pub", {
|
|
918
|
+
src: path,
|
|
919
|
+
dependencies,
|
|
920
|
+
parentComponent,
|
|
921
|
+
filename: pubFiles.join(", "),
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Function to create bom string for cpp projects
|
|
927
|
+
*
|
|
928
|
+
* @param {string} path to the project
|
|
929
|
+
* @param {Object} options Parse options from the cli
|
|
930
|
+
* @returns {Object} BOM object
|
|
931
|
+
*/
|
|
932
|
+
export function createCppBom(path, options) {
|
|
933
|
+
let parentComponent;
|
|
934
|
+
let dependencies = [];
|
|
935
|
+
const addedParentComponentsMap = {};
|
|
936
|
+
const colliderLockFiles = getAllFiles(
|
|
937
|
+
path,
|
|
938
|
+
`${options.multiProject ? "**/" : ""}collider.lock`,
|
|
939
|
+
options,
|
|
940
|
+
);
|
|
941
|
+
const conanLockFiles = getAllFiles(
|
|
942
|
+
path,
|
|
943
|
+
`${options.multiProject ? "**/" : ""}conan.lock`,
|
|
944
|
+
options,
|
|
945
|
+
);
|
|
946
|
+
const conanFiles = getAllFiles(
|
|
947
|
+
path,
|
|
948
|
+
`${options.multiProject ? "**/" : ""}conanfile.txt`,
|
|
949
|
+
options,
|
|
950
|
+
);
|
|
951
|
+
let cmakeLikeFiles = [];
|
|
952
|
+
const mesonBuildFiles = getAllFiles(
|
|
953
|
+
path,
|
|
954
|
+
`${options.multiProject ? "**/" : ""}meson.build`,
|
|
955
|
+
options,
|
|
956
|
+
);
|
|
957
|
+
if (mesonBuildFiles?.length) {
|
|
958
|
+
cmakeLikeFiles = cmakeLikeFiles.concat(mesonBuildFiles);
|
|
959
|
+
}
|
|
960
|
+
cmakeLikeFiles = cmakeLikeFiles.concat(
|
|
961
|
+
getAllFiles(
|
|
962
|
+
path,
|
|
963
|
+
`${options.multiProject ? "**/" : ""}CMakeLists.txt`,
|
|
964
|
+
options,
|
|
965
|
+
),
|
|
966
|
+
);
|
|
967
|
+
const cmakeFiles = getAllFiles(
|
|
968
|
+
path,
|
|
969
|
+
`${options.multiProject ? "**/" : ""}*.cmake`,
|
|
970
|
+
options,
|
|
971
|
+
);
|
|
972
|
+
if (cmakeFiles?.length) {
|
|
973
|
+
cmakeLikeFiles = cmakeLikeFiles.concat(cmakeFiles);
|
|
974
|
+
}
|
|
975
|
+
let pkgList = [];
|
|
976
|
+
let parentComponentDependencies = [];
|
|
977
|
+
if (conanLockFiles.length) {
|
|
978
|
+
for (const f of conanLockFiles) {
|
|
979
|
+
if (DEBUG_MODE) {
|
|
980
|
+
console.log(`Parsing ${f}`);
|
|
981
|
+
}
|
|
982
|
+
const conanLockData = readFileSync(f, { encoding: "utf-8" });
|
|
983
|
+
const {
|
|
984
|
+
pkgList: conanPkgList,
|
|
985
|
+
dependencies: conanDependencies,
|
|
986
|
+
parentComponentDependencies: parentCompDeps,
|
|
987
|
+
} = parseConanLockData(conanLockData);
|
|
988
|
+
|
|
989
|
+
if (conanPkgList.length) {
|
|
990
|
+
pkgList = pkgList.concat(conanPkgList);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
if (Object.keys(conanDependencies).length) {
|
|
994
|
+
dependencies = mergeDependencies(
|
|
995
|
+
dependencies,
|
|
996
|
+
Object.keys(conanDependencies).map((dependentBomRef) => ({
|
|
997
|
+
ref: dependentBomRef,
|
|
998
|
+
dependsOn: conanDependencies[dependentBomRef],
|
|
999
|
+
})),
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
parentComponentDependencies = parentCompDeps;
|
|
1004
|
+
}
|
|
1005
|
+
} else if (conanFiles.length) {
|
|
1006
|
+
for (const f of conanFiles) {
|
|
1007
|
+
if (DEBUG_MODE) {
|
|
1008
|
+
console.log(`Parsing ${f}`);
|
|
1009
|
+
}
|
|
1010
|
+
const conanData = readFileSync(f, { encoding: "utf-8" });
|
|
1011
|
+
const dlist = parseConanData(conanData);
|
|
1012
|
+
if (dlist?.length) {
|
|
1013
|
+
pkgList = pkgList.concat(dlist);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
if (colliderLockFiles.length) {
|
|
1018
|
+
for (const f of colliderLockFiles) {
|
|
1019
|
+
if (DEBUG_MODE) {
|
|
1020
|
+
console.log(`Parsing ${f}`);
|
|
1021
|
+
}
|
|
1022
|
+
const colliderLockData = readFileSync(f, { encoding: "utf-8" });
|
|
1023
|
+
const {
|
|
1024
|
+
pkgList: colliderPkgList,
|
|
1025
|
+
dependencies: colliderDependencies,
|
|
1026
|
+
parentComponentDependencies: parentCompDeps,
|
|
1027
|
+
} = parseColliderLockData(colliderLockData, f);
|
|
1028
|
+
|
|
1029
|
+
if (colliderPkgList.length) {
|
|
1030
|
+
pkgList = pkgList.concat(colliderPkgList);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
if (Object.keys(colliderDependencies).length) {
|
|
1034
|
+
dependencies = mergeDependencies(
|
|
1035
|
+
dependencies,
|
|
1036
|
+
Object.keys(colliderDependencies).map((dependentBomRef) => ({
|
|
1037
|
+
ref: dependentBomRef,
|
|
1038
|
+
dependsOn: colliderDependencies[dependentBomRef],
|
|
1039
|
+
})),
|
|
1040
|
+
);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
if (parentCompDeps.length) {
|
|
1044
|
+
parentComponentDependencies = [
|
|
1045
|
+
...new Set(parentComponentDependencies.concat(parentCompDeps)),
|
|
1046
|
+
];
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
if (cmakeLikeFiles.length) {
|
|
1051
|
+
const beforeCmake = pkgList.length;
|
|
1052
|
+
for (const f of cmakeLikeFiles) {
|
|
1053
|
+
if (DEBUG_MODE) {
|
|
1054
|
+
console.log(`Parsing ${f}`);
|
|
1055
|
+
}
|
|
1056
|
+
const basePath = dirname(f);
|
|
1057
|
+
const retMap = parseCmakeLikeFile(f, "generic");
|
|
1058
|
+
if (retMap.pkgList?.length) {
|
|
1059
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
1060
|
+
}
|
|
1061
|
+
if (
|
|
1062
|
+
basePath === path &&
|
|
1063
|
+
retMap.parentComponent &&
|
|
1064
|
+
Object.keys(retMap.parentComponent).length
|
|
1065
|
+
) {
|
|
1066
|
+
if (!parentComponent) {
|
|
1067
|
+
parentComponent = retMap.parentComponent;
|
|
1068
|
+
} else {
|
|
1069
|
+
parentComponent.components = parentComponent.components || [];
|
|
1070
|
+
if (!addedParentComponentsMap[retMap.parentComponent.name]) {
|
|
1071
|
+
parentComponent.components.push(retMap.parentComponent);
|
|
1072
|
+
addedParentComponentsMap[retMap.parentComponent.name] = true;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
} else if (
|
|
1076
|
+
retMap.parentComponent &&
|
|
1077
|
+
Object.keys(retMap.parentComponent).length &&
|
|
1078
|
+
!addedParentComponentsMap[retMap.parentComponent.name]
|
|
1079
|
+
) {
|
|
1080
|
+
retMap.parentComponent.type = "library";
|
|
1081
|
+
pkgList.push(retMap.parentComponent);
|
|
1082
|
+
}
|
|
1083
|
+
// Retain the dependency tree from cmake
|
|
1084
|
+
if (retMap.dependenciesList) {
|
|
1085
|
+
if (dependencies.length) {
|
|
1086
|
+
dependencies = mergeDependencies(
|
|
1087
|
+
dependencies,
|
|
1088
|
+
retMap.dependenciesList,
|
|
1089
|
+
parentComponent,
|
|
1090
|
+
);
|
|
1091
|
+
} else {
|
|
1092
|
+
dependencies = retMap.dependenciesList;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
// Only the entries this loop appended state version *requirements* that
|
|
1097
|
+
// several files may repeat. The conan and collider entries above name
|
|
1098
|
+
// resolved versions and are left as they are.
|
|
1099
|
+
pkgList = pkgList
|
|
1100
|
+
.slice(0, beforeCmake)
|
|
1101
|
+
.concat(collapseCmakeVersions(pkgList.slice(beforeCmake)));
|
|
1102
|
+
}
|
|
1103
|
+
// CMake describes how a project is built from source. An image or an OS
|
|
1104
|
+
// installation carries build output, not a build tree, so resolving CMake
|
|
1105
|
+
// context over every directory of an exploded rootfs finds nothing and costs
|
|
1106
|
+
// a filesystem walk and a git invocation per directory.
|
|
1107
|
+
const cmakeContext = hasAnyProjectType(
|
|
1108
|
+
["docker", "oci", "container", "os"],
|
|
1109
|
+
options,
|
|
1110
|
+
false,
|
|
1111
|
+
)
|
|
1112
|
+
? {
|
|
1113
|
+
rootProject: undefined,
|
|
1114
|
+
findPackages: new Map(),
|
|
1115
|
+
submodules: [],
|
|
1116
|
+
fetchDeps: [],
|
|
1117
|
+
boundaries: new Map(),
|
|
1118
|
+
}
|
|
1119
|
+
: resolveCmakeContext(path, options);
|
|
1120
|
+
if (cmakeContext.rootProject?.version && parentComponent) {
|
|
1121
|
+
const resolvedVersion = cmakeContext.rootProject.version;
|
|
1122
|
+
const scrapedVersion = parentComponent.version;
|
|
1123
|
+
if (!scrapedVersion || scrapedVersion.includes("${")) {
|
|
1124
|
+
parentComponent.version = resolvedVersion;
|
|
1125
|
+
applyPurl(
|
|
1126
|
+
parentComponent,
|
|
1127
|
+
tryBuildPurl({
|
|
1128
|
+
type: "generic",
|
|
1129
|
+
namespace: parentComponent.group || null,
|
|
1130
|
+
name: parentComponent.name,
|
|
1131
|
+
version: resolvedVersion,
|
|
1132
|
+
}),
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
if (cmakeContext.findPackages.size) {
|
|
1137
|
+
for (const pkg of pkgList) {
|
|
1138
|
+
if (pkg.version) {
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
const resolved =
|
|
1142
|
+
cmakeContext.findPackages.get(pkg.name) ||
|
|
1143
|
+
cmakeContext.findPackages.get(pkg.name.toUpperCase());
|
|
1144
|
+
if (resolved) {
|
|
1145
|
+
pkg.version = resolved;
|
|
1146
|
+
applyPurl(
|
|
1147
|
+
pkg,
|
|
1148
|
+
tryBuildPurl({
|
|
1149
|
+
type: "generic",
|
|
1150
|
+
name: pkg.name,
|
|
1151
|
+
version: resolved,
|
|
1152
|
+
}),
|
|
1153
|
+
);
|
|
1154
|
+
pkg.properties = pkg.properties || [];
|
|
1155
|
+
pkg.properties.push({
|
|
1156
|
+
name: "cdx:cmake:resolvedVia",
|
|
1157
|
+
value: "cmake-cache",
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
for (const dep of cmakeContext.fetchDeps) {
|
|
1163
|
+
const depPurl = buildDependentPurl(dep.url, dep.version);
|
|
1164
|
+
const depRef = depPurl
|
|
1165
|
+
? decodeURIComponent(depPurl)
|
|
1166
|
+
: `library:${dep.name}:${dep.version || ""}`;
|
|
1167
|
+
const depComponent = {
|
|
1168
|
+
name: dep.name,
|
|
1169
|
+
version: dep.version || "",
|
|
1170
|
+
type: "library",
|
|
1171
|
+
purl: depPurl,
|
|
1172
|
+
"bom-ref": depRef,
|
|
1173
|
+
evidence: {
|
|
1174
|
+
identity: {
|
|
1175
|
+
field: "purl",
|
|
1176
|
+
confidence: 0.6,
|
|
1177
|
+
methods: [
|
|
1178
|
+
{
|
|
1179
|
+
technique: "manifest-analysis",
|
|
1180
|
+
confidence: 0.6,
|
|
1181
|
+
value: "FetchContent gitclone script",
|
|
1182
|
+
},
|
|
1183
|
+
],
|
|
1184
|
+
},
|
|
1185
|
+
},
|
|
1186
|
+
properties: [
|
|
1187
|
+
{ name: "cdx:cmake:depKind", value: "fetch" },
|
|
1188
|
+
{ name: "cdx:cmake:resolvedVia", value: "gitclone-script" },
|
|
1189
|
+
],
|
|
1190
|
+
};
|
|
1191
|
+
if (dep.sourceDir) {
|
|
1192
|
+
depComponent.properties.push({
|
|
1193
|
+
name: "cdx:cmake:sourceDir",
|
|
1194
|
+
value: dep.sourceDir,
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
pkgList.push(depComponent);
|
|
1198
|
+
}
|
|
1199
|
+
for (const sub of cmakeContext.submodules) {
|
|
1200
|
+
const subPurl = buildDependentPurl(sub.url, sub.version);
|
|
1201
|
+
const subRef = subPurl
|
|
1202
|
+
? decodeURIComponent(subPurl)
|
|
1203
|
+
: `library:${sub.name}:${sub.version || ""}`;
|
|
1204
|
+
const props = [
|
|
1205
|
+
{ name: "cdx:cmake:depKind", value: "submodule" },
|
|
1206
|
+
{ name: "cdx:cmake:resolvedVia", value: "git-submodule" },
|
|
1207
|
+
];
|
|
1208
|
+
if (sub.uninitialised) {
|
|
1209
|
+
props.push({ name: "cdx:cmake:uninitialised", value: "true" });
|
|
1210
|
+
}
|
|
1211
|
+
if (sub.path) {
|
|
1212
|
+
props.push({ name: "cdx:cmake:sourceDir", value: sub.path });
|
|
1213
|
+
}
|
|
1214
|
+
pkgList.push({
|
|
1215
|
+
name: sub.name,
|
|
1216
|
+
version: sub.version || "",
|
|
1217
|
+
type: "library",
|
|
1218
|
+
purl: subPurl,
|
|
1219
|
+
"bom-ref": subRef,
|
|
1220
|
+
evidence: {
|
|
1221
|
+
identity: {
|
|
1222
|
+
field: "purl",
|
|
1223
|
+
confidence: 0.6,
|
|
1224
|
+
methods: [
|
|
1225
|
+
{
|
|
1226
|
+
technique: "manifest-analysis",
|
|
1227
|
+
confidence: 0.6,
|
|
1228
|
+
value: "git submodule status",
|
|
1229
|
+
},
|
|
1230
|
+
],
|
|
1231
|
+
},
|
|
1232
|
+
},
|
|
1233
|
+
properties: props,
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
// The need for java >= 21 with atom is causing confusions since there could be C projects
|
|
1237
|
+
// inside of other project types. So we currently limit this analyis only when -t argument
|
|
1238
|
+
// is used.
|
|
1239
|
+
if (
|
|
1240
|
+
!hasAnyProjectType(["docker", "oci", "container", "os"], options, false) &&
|
|
1241
|
+
(!options.createMultiXBom || options.deep)
|
|
1242
|
+
) {
|
|
1243
|
+
let osPkgsList = [];
|
|
1244
|
+
// Case 1: Development libraries installed in this OS environment might be used for build
|
|
1245
|
+
// We collect OS packages with the word dev in the name using osquery here
|
|
1246
|
+
// rpm, deb and ebuild are supported
|
|
1247
|
+
// TODO: For archlinux and alpine users we need a different mechanism to collect this information
|
|
1248
|
+
for (const queryCategory of Object.keys(cosDbQueries)) {
|
|
1249
|
+
const queryObj = cosDbQueries[queryCategory];
|
|
1250
|
+
const results = executeOsQuery(queryObj.query);
|
|
1251
|
+
const dlist = convertOSQueryResults(
|
|
1252
|
+
queryCategory,
|
|
1253
|
+
queryObj,
|
|
1254
|
+
results,
|
|
1255
|
+
true,
|
|
1256
|
+
{
|
|
1257
|
+
deb: executeDpkgList,
|
|
1258
|
+
rpm: executeRpmList,
|
|
1259
|
+
apk: executeApkList,
|
|
1260
|
+
ebuild: executeEqueryList,
|
|
1261
|
+
alpm: executeAlpmList,
|
|
1262
|
+
},
|
|
1263
|
+
);
|
|
1264
|
+
if (dlist?.length) {
|
|
1265
|
+
osPkgsList = osPkgsList.concat(dlist);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
// Now we check with atom and attempt to detect all external modules via usages
|
|
1269
|
+
// We pass the current list of packages so that we enhance the current list and replace
|
|
1270
|
+
// components inadvertently. For example, we might resolved a name, version and url information already via cmake
|
|
1271
|
+
const retMap = getCppModules(path, options, osPkgsList, pkgList);
|
|
1272
|
+
if (retMap.pkgList?.length) {
|
|
1273
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
1274
|
+
}
|
|
1275
|
+
if (retMap.dependenciesList) {
|
|
1276
|
+
if (dependencies.length) {
|
|
1277
|
+
dependencies = mergeDependencies(
|
|
1278
|
+
dependencies,
|
|
1279
|
+
retMap.dependenciesList,
|
|
1280
|
+
parentComponent,
|
|
1281
|
+
);
|
|
1282
|
+
} else {
|
|
1283
|
+
dependencies = retMap.dependenciesList;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
if (!parentComponent) {
|
|
1287
|
+
parentComponent = retMap.parentComponent;
|
|
1288
|
+
} else {
|
|
1289
|
+
parentComponent.components = parentComponent.components || [];
|
|
1290
|
+
if (
|
|
1291
|
+
retMap?.parentComponent?.name &&
|
|
1292
|
+
!addedParentComponentsMap[retMap.parentComponent.name]
|
|
1293
|
+
) {
|
|
1294
|
+
parentComponent.components.push(retMap.parentComponent);
|
|
1295
|
+
addedParentComponentsMap[retMap.parentComponent.name] = true;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
if (!options.createMultiXBom) {
|
|
1300
|
+
if (!parentComponent) {
|
|
1301
|
+
parentComponent = createDefaultParentComponent(path, "generic", options);
|
|
1302
|
+
}
|
|
1303
|
+
options.parentComponent = parentComponent;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
if (parentComponent && parentComponentDependencies.length) {
|
|
1307
|
+
dependencies = mergeDependencies(dependencies, [
|
|
1308
|
+
{
|
|
1309
|
+
ref: parentComponent["bom-ref"],
|
|
1310
|
+
dependsOn: parentComponentDependencies,
|
|
1311
|
+
},
|
|
1312
|
+
]);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
if (parentComponent) {
|
|
1316
|
+
sanitizeUnresolvedPurl(parentComponent);
|
|
1317
|
+
if (parentComponent.components) {
|
|
1318
|
+
for (const sub of parentComponent.components) {
|
|
1319
|
+
sanitizeUnresolvedPurl(sub);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
for (const pkg of pkgList) {
|
|
1324
|
+
sanitizeUnresolvedPurl(pkg);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
return buildBomNSData(options, pkgList, "generic", {
|
|
1328
|
+
src: path,
|
|
1329
|
+
parentComponent,
|
|
1330
|
+
dependencies,
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
/**
|
|
1335
|
+
* Function to create bom string for clojure projects
|
|
1336
|
+
*
|
|
1337
|
+
* @param {string} path to the project
|
|
1338
|
+
* @param {Object} options Parse options from the cli
|
|
1339
|
+
* @returns {Object} BOM object
|
|
1340
|
+
*/
|
|
1341
|
+
export function createClojureBom(path, options) {
|
|
1342
|
+
const ednFiles = getAllFiles(
|
|
1343
|
+
path,
|
|
1344
|
+
`${options.multiProject ? "**/" : ""}deps.edn`,
|
|
1345
|
+
options,
|
|
1346
|
+
);
|
|
1347
|
+
const leinFiles = getAllFiles(
|
|
1348
|
+
path,
|
|
1349
|
+
`${options.multiProject ? "**/" : ""}project.clj`,
|
|
1350
|
+
options,
|
|
1351
|
+
);
|
|
1352
|
+
let pkgList = [];
|
|
1353
|
+
if (leinFiles.length) {
|
|
1354
|
+
let LEIN_ARGS = ["deps", ":tree-data"];
|
|
1355
|
+
if (readEnvironmentVariable("LEIN_ARGS")) {
|
|
1356
|
+
LEIN_ARGS = readEnvironmentVariable("LEIN_ARGS").split(" ");
|
|
1357
|
+
}
|
|
1358
|
+
for (const f of leinFiles) {
|
|
1359
|
+
if (DEBUG_MODE) {
|
|
1360
|
+
console.log(`Parsing ${f}`);
|
|
1361
|
+
}
|
|
1362
|
+
const basePath = dirname(f);
|
|
1363
|
+
console.log("Executing", LEIN_CMD, "in", basePath);
|
|
1364
|
+
const result = safeSpawnSync(LEIN_CMD, LEIN_ARGS, {
|
|
1365
|
+
cwd: basePath,
|
|
1366
|
+
});
|
|
1367
|
+
if (result.status !== 0 || result.error) {
|
|
1368
|
+
if (result.stderr) {
|
|
1369
|
+
console.error(result.stdout, result.stderr);
|
|
1370
|
+
options.failOnError && process.exit(1);
|
|
1371
|
+
}
|
|
1372
|
+
console.log(
|
|
1373
|
+
"Check if the correct version of lein is installed and available in PATH. Falling back to manual parsing.",
|
|
1374
|
+
);
|
|
1375
|
+
if (DEBUG_MODE) {
|
|
1376
|
+
console.log(`Parsing ${f}`);
|
|
1377
|
+
}
|
|
1378
|
+
const leinData = readFileSync(f, { encoding: "utf-8" });
|
|
1379
|
+
const dlist = parseLeiningenData(leinData);
|
|
1380
|
+
if (dlist?.length) {
|
|
1381
|
+
pkgList = pkgList.concat(dlist);
|
|
1382
|
+
}
|
|
1383
|
+
} else {
|
|
1384
|
+
const stdout = result.stdout;
|
|
1385
|
+
if (stdout) {
|
|
1386
|
+
const cmdOutput = Buffer.from(stdout).toString();
|
|
1387
|
+
const dlist = parseLeinDep(cmdOutput);
|
|
1388
|
+
if (dlist?.length) {
|
|
1389
|
+
pkgList = pkgList.concat(dlist);
|
|
1390
|
+
}
|
|
1391
|
+
} else {
|
|
1392
|
+
console.error("lein unexpectedly didn't return any output");
|
|
1393
|
+
options.failOnError && process.exit(1);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
return buildBomNSData(options, pkgList, "clojars", {
|
|
1398
|
+
src: path,
|
|
1399
|
+
filename: leinFiles.join(", "),
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
if (ednFiles.length && !hasAnyProjectType(["oci"], options, false)) {
|
|
1403
|
+
let CLJ_ARGS = ["-Stree"];
|
|
1404
|
+
if (readEnvironmentVariable("CLJ_ARGS")) {
|
|
1405
|
+
CLJ_ARGS = readEnvironmentVariable("CLJ_ARGS").split(" ");
|
|
1406
|
+
}
|
|
1407
|
+
for (const f of ednFiles) {
|
|
1408
|
+
const basePath = dirname(f);
|
|
1409
|
+
console.log("Executing", CLJ_CMD, "in", basePath);
|
|
1410
|
+
const result = safeSpawnSync(CLJ_CMD, CLJ_ARGS, {
|
|
1411
|
+
cwd: basePath,
|
|
1412
|
+
});
|
|
1413
|
+
if (result.status !== 0 || result.error) {
|
|
1414
|
+
if (result.stderr) {
|
|
1415
|
+
console.error(result.stdout, result.stderr);
|
|
1416
|
+
options.failOnError && process.exit(1);
|
|
1417
|
+
}
|
|
1418
|
+
console.log(
|
|
1419
|
+
"Check if the correct version of clojure cli is installed and available in PATH. Falling back to manual parsing.",
|
|
1420
|
+
);
|
|
1421
|
+
if (DEBUG_MODE) {
|
|
1422
|
+
console.log(`Parsing ${f}`);
|
|
1423
|
+
}
|
|
1424
|
+
const ednData = readFileSync(f, { encoding: "utf-8" });
|
|
1425
|
+
const dlist = parseEdnData(ednData);
|
|
1426
|
+
if (dlist?.length) {
|
|
1427
|
+
pkgList = pkgList.concat(dlist);
|
|
1428
|
+
}
|
|
1429
|
+
} else {
|
|
1430
|
+
const stdout = result.stdout;
|
|
1431
|
+
if (stdout) {
|
|
1432
|
+
const cmdOutput = Buffer.from(stdout).toString();
|
|
1433
|
+
const dlist = parseCljDep(cmdOutput);
|
|
1434
|
+
if (dlist?.length) {
|
|
1435
|
+
pkgList = pkgList.concat(dlist);
|
|
1436
|
+
}
|
|
1437
|
+
} else {
|
|
1438
|
+
console.error("clj unexpectedly didn't return any output");
|
|
1439
|
+
options.failOnError && process.exit(1);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
return buildBomNSData(options, pkgList, "clojars", {
|
|
1444
|
+
src: path,
|
|
1445
|
+
filename: ednFiles.join(", "),
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
return {};
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* Function to create bom string for Haskell projects
|
|
1454
|
+
*
|
|
1455
|
+
* @param {string} path to the project
|
|
1456
|
+
* @param {Object} options Parse options from the cli
|
|
1457
|
+
* @returns {Object} BOM object
|
|
1458
|
+
*/
|
|
1459
|
+
export function createHaskellBom(path, options) {
|
|
1460
|
+
const cabalFiles = getAllFiles(
|
|
1461
|
+
path,
|
|
1462
|
+
`${options.multiProject ? "**/" : ""}cabal.project.freeze`,
|
|
1463
|
+
options,
|
|
1464
|
+
);
|
|
1465
|
+
let pkgList = [];
|
|
1466
|
+
if (cabalFiles.length) {
|
|
1467
|
+
for (const f of cabalFiles) {
|
|
1468
|
+
if (DEBUG_MODE) {
|
|
1469
|
+
console.log(`Parsing ${f}`);
|
|
1470
|
+
}
|
|
1471
|
+
const cabalData = readFileSync(f, { encoding: "utf-8" });
|
|
1472
|
+
const dlist = parseCabalData(cabalData);
|
|
1473
|
+
if (dlist?.length) {
|
|
1474
|
+
pkgList = pkgList.concat(dlist);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
return buildBomNSData(options, pkgList, "hackage", {
|
|
1478
|
+
src: path,
|
|
1479
|
+
filename: cabalFiles.join(", "),
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
return {};
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
/**
|
|
1486
|
+
* Function to create bom string for Elixir projects
|
|
1487
|
+
*
|
|
1488
|
+
* @param {string} path to the project
|
|
1489
|
+
* @param {Object} options Parse options from the cli
|
|
1490
|
+
* @returns {Object} BOM object
|
|
1491
|
+
*/
|
|
1492
|
+
export function createElixirBom(path, options) {
|
|
1493
|
+
const mixFiles = getAllFiles(
|
|
1494
|
+
path,
|
|
1495
|
+
`${options.multiProject ? "**/" : ""}mix.lock`,
|
|
1496
|
+
options,
|
|
1497
|
+
);
|
|
1498
|
+
let pkgList = [];
|
|
1499
|
+
if (mixFiles.length) {
|
|
1500
|
+
for (const f of mixFiles) {
|
|
1501
|
+
if (DEBUG_MODE) {
|
|
1502
|
+
console.log(`Parsing ${f}`);
|
|
1503
|
+
}
|
|
1504
|
+
const mixData = readFileSync(f, { encoding: "utf-8" });
|
|
1505
|
+
const dlist = parseMixLockData(mixData);
|
|
1506
|
+
if (dlist?.length) {
|
|
1507
|
+
pkgList = pkgList.concat(dlist);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
return buildBomNSData(options, pkgList, "hex", {
|
|
1511
|
+
src: path,
|
|
1512
|
+
filename: mixFiles.join(", "),
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
return {};
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
/**
|
|
1519
|
+
* Function to create bom string for swift projects
|
|
1520
|
+
*
|
|
1521
|
+
* @param {string} path to the project
|
|
1522
|
+
* @param {Object} options Parse options from the cli
|
|
1523
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
1524
|
+
*/
|
|
1525
|
+
export async function createSwiftBom(path, options) {
|
|
1526
|
+
const swiftFiles = getAllFiles(
|
|
1527
|
+
path,
|
|
1528
|
+
`${options.multiProject ? "**/" : ""}Package*.swift`,
|
|
1529
|
+
options,
|
|
1530
|
+
);
|
|
1531
|
+
const pkgResolvedFiles = getAllFiles(
|
|
1532
|
+
path,
|
|
1533
|
+
`${options.multiProject ? "**/" : ""}Package.resolved`,
|
|
1534
|
+
options,
|
|
1535
|
+
);
|
|
1536
|
+
let pkgList = [];
|
|
1537
|
+
let dependencies = [];
|
|
1538
|
+
let parentComponent = {};
|
|
1539
|
+
const completedPath = [];
|
|
1540
|
+
let packageArgsMessageShown = false;
|
|
1541
|
+
if (pkgResolvedFiles.length) {
|
|
1542
|
+
for (const f of pkgResolvedFiles) {
|
|
1543
|
+
if (!parentComponent || !Object.keys(parentComponent).length) {
|
|
1544
|
+
parentComponent = createDefaultParentComponent(f, "swift", options);
|
|
1545
|
+
}
|
|
1546
|
+
if (DEBUG_MODE) {
|
|
1547
|
+
console.log("Parsing", f);
|
|
1548
|
+
}
|
|
1549
|
+
const dlist = parseSwiftResolved(f);
|
|
1550
|
+
if (dlist?.length) {
|
|
1551
|
+
pkgList = pkgList.concat(dlist);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
thoughtLog(
|
|
1555
|
+
`It looks like we have ${pkgResolvedFiles.length} Package.resolved files, which is good. To compute the dependency tree, let's try using the swift package command 📦.`,
|
|
1556
|
+
);
|
|
1557
|
+
}
|
|
1558
|
+
if (swiftFiles.length) {
|
|
1559
|
+
for (const f of swiftFiles) {
|
|
1560
|
+
const basePath = dirname(f);
|
|
1561
|
+
if (completedPath.includes(basePath)) {
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
let treeData;
|
|
1565
|
+
let packageArgs = ["package"];
|
|
1566
|
+
// Additional arguments to pass to the swift package command.
|
|
1567
|
+
// Example: --swift-sdks-path <swift-sdks-path> --jobs <jobs>
|
|
1568
|
+
if (readEnvironmentVariable("SWIFT_PACKAGE_ARGS")) {
|
|
1569
|
+
packageArgs = packageArgs.concat(
|
|
1570
|
+
readEnvironmentVariable("SWIFT_PACKAGE_ARGS").split(" "),
|
|
1571
|
+
);
|
|
1572
|
+
if (!packageArgsMessageShown) {
|
|
1573
|
+
thoughtLog(
|
|
1574
|
+
`Wait, let's use the additional arguments '${readEnvironmentVariable("SWIFT_PACKAGE_ARGS")}' for the swift package command.`,
|
|
1575
|
+
);
|
|
1576
|
+
packageArgsMessageShown = true;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
packageArgs = packageArgs.concat([
|
|
1580
|
+
"show-dependencies",
|
|
1581
|
+
"--format",
|
|
1582
|
+
"json",
|
|
1583
|
+
]);
|
|
1584
|
+
let swiftCommand = SWIFT_CMD;
|
|
1585
|
+
if (swiftCommand.startsWith("xcrun")) {
|
|
1586
|
+
swiftCommand = "xcrun";
|
|
1587
|
+
packageArgs = ["swift"].concat(packageArgs);
|
|
1588
|
+
}
|
|
1589
|
+
if (DEBUG_MODE) {
|
|
1590
|
+
console.log(
|
|
1591
|
+
`Executing '${swiftCommand} ${packageArgs.join(" ")}' in ${basePath}. Please wait ...`,
|
|
1592
|
+
);
|
|
1593
|
+
}
|
|
1594
|
+
const result = safeSpawnSync(swiftCommand, packageArgs, {
|
|
1595
|
+
cwd: basePath,
|
|
1596
|
+
});
|
|
1597
|
+
if (result.stdout) {
|
|
1598
|
+
completedPath.push(basePath);
|
|
1599
|
+
treeData = Buffer.from(result.stdout).toString();
|
|
1600
|
+
const retData = parseSwiftJsonTree(treeData, f);
|
|
1601
|
+
if (retData.rootList?.length) {
|
|
1602
|
+
if (!Object.keys(parentComponent).length) {
|
|
1603
|
+
parentComponent = retData.rootList[0];
|
|
1604
|
+
if (retData.rootList.length > 1) {
|
|
1605
|
+
if (!parentComponent.components) {
|
|
1606
|
+
parentComponent.components = [];
|
|
1607
|
+
}
|
|
1608
|
+
for (const p of retData.rootList.splice(0, 1)) {
|
|
1609
|
+
parentComponent.components.push(p);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
} else {
|
|
1613
|
+
if (!parentComponent.components) {
|
|
1614
|
+
parentComponent.components = [];
|
|
1615
|
+
}
|
|
1616
|
+
parentComponent.components.concat(retData.rootList);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
pkgList = pkgList.concat(retData.pkgList);
|
|
1620
|
+
if (retData.dependenciesList) {
|
|
1621
|
+
dependencies = mergeDependencies(
|
|
1622
|
+
dependencies,
|
|
1623
|
+
retData.dependenciesList,
|
|
1624
|
+
parentComponent,
|
|
1625
|
+
);
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
if (result.status !== 0 || result.error) {
|
|
1629
|
+
if (result?.stderr?.includes("Source files for target")) {
|
|
1630
|
+
console.log(
|
|
1631
|
+
"The Sources directory is missing. Please run cdxgen from the directory that contains the complete source code.",
|
|
1632
|
+
);
|
|
1633
|
+
thoughtLog(
|
|
1634
|
+
`It looks like the 'Sources' directory is missing, so we are missing the components and dependencies for '${basename(basePath)}'.`,
|
|
1635
|
+
);
|
|
1636
|
+
} else if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") !== "true") {
|
|
1637
|
+
console.log(
|
|
1638
|
+
"Consider using the cdxgen container image (`ghcr.io/cdxgen/cdxgen`), which includes Swift and additional build tools.",
|
|
1639
|
+
);
|
|
1640
|
+
if (!isMac) {
|
|
1641
|
+
console.log("Alternatively, try building this project from a Mac.");
|
|
1642
|
+
thoughtLog(
|
|
1643
|
+
"I'm wondering if the results might be better on a Mac 🤔.",
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
console.error(result.stderr);
|
|
1648
|
+
options.failOnError && process.exit(1);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
if (shouldFetchLicense()) {
|
|
1653
|
+
pkgList = await getSwiftPackageMetadata(pkgList);
|
|
1654
|
+
}
|
|
1655
|
+
return buildBomNSData(options, pkgList, "swift", {
|
|
1656
|
+
src: path,
|
|
1657
|
+
filename: swiftFiles.join(", "),
|
|
1658
|
+
parentComponent,
|
|
1659
|
+
dependencies,
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
/**
|
|
1664
|
+
* Function to create bom string for cocoa projects
|
|
1665
|
+
*
|
|
1666
|
+
* @param {string} path to the project
|
|
1667
|
+
* @param {Object} options Parse options from the cli
|
|
1668
|
+
* @returns {Promise<Object | undefined>} Promise resolving to a BOM object, or `undefined` when no Podfiles are found
|
|
1669
|
+
*/
|
|
1670
|
+
export async function createCocoaBom(path, options) {
|
|
1671
|
+
const cocoaFiles = getAllFiles(
|
|
1672
|
+
path,
|
|
1673
|
+
`${options.multiProject ? "**/" : ""}Podfile`,
|
|
1674
|
+
options,
|
|
1675
|
+
);
|
|
1676
|
+
if (cocoaFiles.length > 1) {
|
|
1677
|
+
thoughtLog(
|
|
1678
|
+
`There are ${cocoaFiles.length} pod files. I will carefully process each one.`,
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
let excludeMessageShown = false;
|
|
1682
|
+
for (const podFile of cocoaFiles) {
|
|
1683
|
+
const projectPath = dirname(podFile);
|
|
1684
|
+
const lockFile = `${podFile}.lock`;
|
|
1685
|
+
let missingLockWarningShown = false;
|
|
1686
|
+
if (!safeExistsSync(lockFile)) {
|
|
1687
|
+
if (options.installDeps) {
|
|
1688
|
+
executePodCommand(["install"], projectPath, options);
|
|
1689
|
+
} else {
|
|
1690
|
+
console.log(
|
|
1691
|
+
"No 'Podfile.lock' found and '--no-install-deps' is set -- A Podfile.lock is needed to parse dependencies!",
|
|
1692
|
+
);
|
|
1693
|
+
missingLockWarningShown = true;
|
|
1694
|
+
options.failOnError && process.exit(1);
|
|
1695
|
+
}
|
|
1696
|
+
} else if (options.deep && options.installDeps) {
|
|
1697
|
+
executePodCommand(["install"], projectPath, options);
|
|
1698
|
+
}
|
|
1699
|
+
if (!safeExistsSync(lockFile)) {
|
|
1700
|
+
if (!missingLockWarningShown) {
|
|
1701
|
+
console.log(
|
|
1702
|
+
`No 'Podfile.lock' found for ${projectPath}. Skipping CocoaPods dependency parsing for this project.`,
|
|
1703
|
+
);
|
|
1704
|
+
}
|
|
1705
|
+
continue;
|
|
1706
|
+
}
|
|
1707
|
+
const parentComponent = await buildObjectForCocoaPod(
|
|
1708
|
+
{
|
|
1709
|
+
name: basename(projectPath),
|
|
1710
|
+
version: "latest",
|
|
1711
|
+
},
|
|
1712
|
+
undefined,
|
|
1713
|
+
"application",
|
|
1714
|
+
);
|
|
1715
|
+
const podfileLock = loadYaml(readFileSync(lockFile, "utf-8"));
|
|
1716
|
+
const pods = await parsePodfileLock(podfileLock, projectPath);
|
|
1717
|
+
const allObjects = new Map();
|
|
1718
|
+
if (options) {
|
|
1719
|
+
// Every remote podspec the scan below reads is known from the lockfile,
|
|
1720
|
+
// so they are fetched in batched rounds rather than one at a time inside
|
|
1721
|
+
// the loop.
|
|
1722
|
+
await prefetchCocoaPodspecs(
|
|
1723
|
+
[...pods.values()].map((pod) => pod.metadata),
|
|
1724
|
+
);
|
|
1725
|
+
}
|
|
1726
|
+
for (const [name, pod] of pods) {
|
|
1727
|
+
allObjects.set(name, await buildObjectForCocoaPod(pod.metadata, options));
|
|
1728
|
+
}
|
|
1729
|
+
const allDependencies = new Map();
|
|
1730
|
+
for (const [name, pod] of pods) {
|
|
1731
|
+
const podDependencies = new Set();
|
|
1732
|
+
if (pod.dependencies) {
|
|
1733
|
+
for (const podDependency of pod.dependencies) {
|
|
1734
|
+
podDependencies.add(podDependency.name);
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
allDependencies.set(name, podDependencies);
|
|
1738
|
+
}
|
|
1739
|
+
const targetDependencies = new Map();
|
|
1740
|
+
if (
|
|
1741
|
+
!readEnvironmentVariable("COCOA_INCLUDED_TARGETS") &&
|
|
1742
|
+
!readEnvironmentVariable("COCOA_EXCLUDED_TARGETS")
|
|
1743
|
+
) {
|
|
1744
|
+
targetDependencies.set("Pods", podfileLock["DEPENDENCIES"]);
|
|
1745
|
+
} else {
|
|
1746
|
+
const result = executePodCommand(
|
|
1747
|
+
["ipc", "podfile-json", "--silent", podFile],
|
|
1748
|
+
projectPath,
|
|
1749
|
+
options,
|
|
1750
|
+
);
|
|
1751
|
+
const resolvedPodFile = JSON.parse(result.stdout);
|
|
1752
|
+
parsePodfileTargets(
|
|
1753
|
+
resolvedPodFile["target_definitions"][0],
|
|
1754
|
+
targetDependencies,
|
|
1755
|
+
);
|
|
1756
|
+
}
|
|
1757
|
+
const usedTargets = new Set(
|
|
1758
|
+
readEnvironmentVariable("COCOA_INCLUDED_TARGETS")
|
|
1759
|
+
? readEnvironmentVariable("COCOA_INCLUDED_TARGETS").split(",")
|
|
1760
|
+
: targetDependencies.keys(),
|
|
1761
|
+
);
|
|
1762
|
+
if (readEnvironmentVariable("COCOA_EXCLUDED_TARGETS")) {
|
|
1763
|
+
readEnvironmentVariable("COCOA_EXCLUDED_TARGETS")
|
|
1764
|
+
.split(",")
|
|
1765
|
+
.forEach((excludedTarget) => {
|
|
1766
|
+
usedTargets.delete(excludedTarget);
|
|
1767
|
+
});
|
|
1768
|
+
if (!excludeMessageShown) {
|
|
1769
|
+
thoughtLog(
|
|
1770
|
+
"Wait, the user wants me to exclude certain targets from this CocoaPods project. Perhaps they don't want dev and test projects included in the SBOM 🤔?",
|
|
1771
|
+
);
|
|
1772
|
+
excludeMessageShown = true;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
let addedObjects = new Set();
|
|
1776
|
+
for (const target of usedTargets) {
|
|
1777
|
+
if (targetDependencies.has(target)) {
|
|
1778
|
+
for (const dependency of targetDependencies.get(target)) {
|
|
1779
|
+
let dependencyName = parseCocoaDependency(dependency, false).name;
|
|
1780
|
+
if (
|
|
1781
|
+
!["false", "0"].includes(
|
|
1782
|
+
readEnvironmentVariable("COCOA_MERGE_SUBSPECS"),
|
|
1783
|
+
)
|
|
1784
|
+
) {
|
|
1785
|
+
dependencyName = dependencyName.split("/")[0];
|
|
1786
|
+
}
|
|
1787
|
+
addedObjects.add(dependencyName);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
// A Podfile target can name a pod that the lockfile does not resolve (a
|
|
1792
|
+
// subspec collapsed by COCOA_MERGE_SUBSPECS, or a pod declared but never
|
|
1793
|
+
// locked). Those names have no entry in allObjects/allDependencies, so every
|
|
1794
|
+
// lookup here is filtered rather than dereferenced — the unguarded version
|
|
1795
|
+
// threw "allDependencies.get(...) is not iterable" and aborted the scan.
|
|
1796
|
+
const bomRefFor = (name) => allObjects.get(name)?.["bom-ref"];
|
|
1797
|
+
const dependenciesOf = (name) => allDependencies.get(name) ?? [];
|
|
1798
|
+
let includedDependencies = [
|
|
1799
|
+
{
|
|
1800
|
+
ref: parentComponent["bom-ref"],
|
|
1801
|
+
dependsOn: [
|
|
1802
|
+
...new Set([...addedObjects].map(bomRefFor).filter(Boolean)),
|
|
1803
|
+
],
|
|
1804
|
+
},
|
|
1805
|
+
];
|
|
1806
|
+
const includedObjects = new Set(addedObjects);
|
|
1807
|
+
while (addedObjects.size !== 0) {
|
|
1808
|
+
const newlyAddedObjects = new Set();
|
|
1809
|
+
for (const addedObject of addedObjects) {
|
|
1810
|
+
for (const dependency of dependenciesOf(addedObject)) {
|
|
1811
|
+
if (!includedObjects.has(dependency)) {
|
|
1812
|
+
includedObjects.add(dependency);
|
|
1813
|
+
newlyAddedObjects.add(dependency);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
addedObjects = newlyAddedObjects;
|
|
1818
|
+
}
|
|
1819
|
+
for (const object of includedObjects) {
|
|
1820
|
+
const ref = bomRefFor(object);
|
|
1821
|
+
if (!ref) {
|
|
1822
|
+
continue;
|
|
1823
|
+
}
|
|
1824
|
+
includedDependencies = mergeDependencies(includedDependencies, [
|
|
1825
|
+
{
|
|
1826
|
+
ref,
|
|
1827
|
+
dependsOn: [
|
|
1828
|
+
...new Set(
|
|
1829
|
+
[...dependenciesOf(object)].map(bomRefFor).filter(Boolean),
|
|
1830
|
+
),
|
|
1831
|
+
],
|
|
1832
|
+
},
|
|
1833
|
+
]);
|
|
1834
|
+
}
|
|
1835
|
+
return buildBomNSData(
|
|
1836
|
+
options,
|
|
1837
|
+
[...includedObjects].map((obj) => allObjects.get(obj)).filter(Boolean),
|
|
1838
|
+
"cocoapods",
|
|
1839
|
+
{
|
|
1840
|
+
src: path,
|
|
1841
|
+
filename: lockFile,
|
|
1842
|
+
dependencies: includedDependencies,
|
|
1843
|
+
parentComponent,
|
|
1844
|
+
},
|
|
1845
|
+
);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
/**
|
|
1850
|
+
* Function to create bom string for Nix flakes
|
|
1851
|
+
*
|
|
1852
|
+
* @param {string} path to the project
|
|
1853
|
+
* @param {Object} options Parse options from the cli
|
|
1854
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
1855
|
+
*/
|
|
1856
|
+
export async function createNixBom(path, options) {
|
|
1857
|
+
let pkgList = [];
|
|
1858
|
+
let dependencies = [];
|
|
1859
|
+
let parentComponent = {};
|
|
1860
|
+
|
|
1861
|
+
const flakeNixFiles = getAllFiles(
|
|
1862
|
+
path,
|
|
1863
|
+
`${options.multiProject ? "**/" : ""}flake.nix`,
|
|
1864
|
+
options,
|
|
1865
|
+
);
|
|
1866
|
+
const flakeLockFiles = getAllFiles(
|
|
1867
|
+
path,
|
|
1868
|
+
`${options.multiProject ? "**/" : ""}flake.lock`,
|
|
1869
|
+
options,
|
|
1870
|
+
);
|
|
1871
|
+
|
|
1872
|
+
for (const flakeNixFile of flakeNixFiles) {
|
|
1873
|
+
if (DEBUG_MODE) {
|
|
1874
|
+
console.log(`Parsing ${flakeNixFile}`);
|
|
1875
|
+
}
|
|
1876
|
+
const { pkgList: nixPkgs, dependencies: nixDeps } =
|
|
1877
|
+
parseFlakeNix(flakeNixFile);
|
|
1878
|
+
if (nixPkgs?.length) {
|
|
1879
|
+
pkgList = pkgList.concat(nixPkgs);
|
|
1880
|
+
}
|
|
1881
|
+
if (nixDeps?.length) {
|
|
1882
|
+
dependencies = dependencies.concat(nixDeps);
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
for (const flakeLockFile of flakeLockFiles) {
|
|
1887
|
+
if (DEBUG_MODE) {
|
|
1888
|
+
console.log(`Parsing ${flakeLockFile}`);
|
|
1889
|
+
}
|
|
1890
|
+
const {
|
|
1891
|
+
pkgList: lockPkgs,
|
|
1892
|
+
dependencies: lockDeps,
|
|
1893
|
+
rootInputs,
|
|
1894
|
+
} = parseFlakeLock(flakeLockFile);
|
|
1895
|
+
if (lockPkgs?.length) {
|
|
1896
|
+
const mergedPkgs = [];
|
|
1897
|
+
const existingNames = new Set();
|
|
1898
|
+
|
|
1899
|
+
for (const lockPkg of lockPkgs) {
|
|
1900
|
+
mergedPkgs.push(lockPkg);
|
|
1901
|
+
existingNames.add(lockPkg.name);
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
for (const nixPkg of pkgList) {
|
|
1905
|
+
if (!existingNames.has(nixPkg.name)) {
|
|
1906
|
+
mergedPkgs.push(nixPkg);
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
pkgList = mergedPkgs;
|
|
1911
|
+
}
|
|
1912
|
+
if (lockDeps?.length) {
|
|
1913
|
+
dependencies = dependencies.concat(lockDeps);
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// Create parent component from flake.lock if found
|
|
1917
|
+
if (!Object.keys(parentComponent).length) {
|
|
1918
|
+
const flakeDir = dirname(flakeLockFile);
|
|
1919
|
+
const projectName = basename(flakeDir);
|
|
1920
|
+
parentComponent = {
|
|
1921
|
+
type: "application",
|
|
1922
|
+
name: projectName,
|
|
1923
|
+
version: "latest",
|
|
1924
|
+
description: `Nix flake project: ${projectName}`,
|
|
1925
|
+
"bom-ref": nixBomRef(projectName),
|
|
1926
|
+
properties: [
|
|
1927
|
+
{
|
|
1928
|
+
name: "internal:SrcFile",
|
|
1929
|
+
value: flakeLockFile,
|
|
1930
|
+
},
|
|
1931
|
+
{
|
|
1932
|
+
name: "cdx:nix:flake_dir",
|
|
1933
|
+
value: flakeDir,
|
|
1934
|
+
},
|
|
1935
|
+
],
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
// Build the root dependency edge here, where the parent component's real
|
|
1940
|
+
// bom-ref is known. parseFlakeLock returns the root's direct inputs as
|
|
1941
|
+
// bom-refs rather than synthesising an edge with a guessed (and dangling)
|
|
1942
|
+
// root ref.
|
|
1943
|
+
if (rootInputs?.length && parentComponent?.["bom-ref"]) {
|
|
1944
|
+
dependencies.push({
|
|
1945
|
+
ref: parentComponent["bom-ref"],
|
|
1946
|
+
dependsOn: [...new Set(rootInputs)],
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
// If no parent component was created from flake.lock, create one from flake.nix
|
|
1952
|
+
if (!Object.keys(parentComponent).length && flakeNixFiles.length > 0) {
|
|
1953
|
+
const flakeDir = dirname(flakeNixFiles[0]);
|
|
1954
|
+
const projectName = basename(flakeDir);
|
|
1955
|
+
parentComponent = {
|
|
1956
|
+
type: "application",
|
|
1957
|
+
name: projectName,
|
|
1958
|
+
version: "latest",
|
|
1959
|
+
description: `Nix flake project: ${projectName}`,
|
|
1960
|
+
"bom-ref": nixBomRef(projectName),
|
|
1961
|
+
properties: [
|
|
1962
|
+
{
|
|
1963
|
+
name: "internal:SrcFile",
|
|
1964
|
+
value: flakeNixFiles[0],
|
|
1965
|
+
},
|
|
1966
|
+
{
|
|
1967
|
+
name: "cdx:nix:flake_dir",
|
|
1968
|
+
value: flakeDir,
|
|
1969
|
+
},
|
|
1970
|
+
],
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
if (pkgList.length || Object.keys(parentComponent).length) {
|
|
1975
|
+
return buildBomNSData(options, pkgList, "nix", {
|
|
1976
|
+
src: path,
|
|
1977
|
+
filename: [...flakeNixFiles, ...flakeLockFiles].join(", "),
|
|
1978
|
+
dependencies,
|
|
1979
|
+
parentComponent,
|
|
1980
|
+
});
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
return {};
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
/**
|
|
1987
|
+
* Function to create bom string for Zig projects.
|
|
1988
|
+
*
|
|
1989
|
+
* Zig moved package management into the build system, so the dependency list
|
|
1990
|
+
* lives in `build.zig.zon` (ZON, not JSON). The resolver walks the full
|
|
1991
|
+
* dependency graph by locating each dependency's manifest through the in-tree
|
|
1992
|
+
* `zig-pkg/` directory or the global cache, producing both a flat component
|
|
1993
|
+
* list and a CycloneDX `dependencies[]` edge list.
|
|
1994
|
+
*
|
|
1995
|
+
* @param {string} path to the project
|
|
1996
|
+
* @param {Object} options Parse options from the cli
|
|
1997
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
1998
|
+
*/
|
|
1999
|
+
export async function createZigBom(path, options) {
|
|
2000
|
+
const pkgList = [];
|
|
2001
|
+
const seenRefs = new Set();
|
|
2002
|
+
let parentComponent = {};
|
|
2003
|
+
let dependencies = [];
|
|
2004
|
+
|
|
2005
|
+
const zonFiles = getAllFiles(
|
|
2006
|
+
path,
|
|
2007
|
+
`${options.multiProject ? "**/" : ""}build.zig.zon`,
|
|
2008
|
+
options,
|
|
2009
|
+
).filter((f) => !/[\\/]zig-pkg[\\/]/.test(f));
|
|
2010
|
+
|
|
2011
|
+
// Vendored manifests under zig-pkg/ describe dependencies, not projects. The
|
|
2012
|
+
// resolver reaches them through their hash, so treating one as a root would
|
|
2013
|
+
// duplicate the component and invent a second parent component.
|
|
2014
|
+
for (const zonFile of zonFiles) {
|
|
2015
|
+
if (DEBUG_MODE) {
|
|
2016
|
+
console.log(`Parsing ${zonFile}`);
|
|
2017
|
+
}
|
|
2018
|
+
const {
|
|
2019
|
+
pkgList: resolvedPkgs,
|
|
2020
|
+
dependencies: resolvedDeps,
|
|
2021
|
+
parentComponent: zonParent,
|
|
2022
|
+
unresolvedCount,
|
|
2023
|
+
} = await resolveZigGraph(zonFile, path, options);
|
|
2024
|
+
// Each root manifest is resolved independently, so a dependency shared by
|
|
2025
|
+
// two workspace members arrives twice. Both the component and its edges
|
|
2026
|
+
// are keyed on bom-ref, so merging on that key is what keeps a
|
|
2027
|
+
// multi-project scan from emitting duplicates.
|
|
2028
|
+
for (const pkg of resolvedPkgs || []) {
|
|
2029
|
+
if (!seenRefs.has(pkg["bom-ref"])) {
|
|
2030
|
+
seenRefs.add(pkg["bom-ref"]);
|
|
2031
|
+
pkgList.push(pkg);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
if (resolvedDeps?.length) {
|
|
2035
|
+
dependencies = mergeDependencies(dependencies, resolvedDeps);
|
|
2036
|
+
}
|
|
2037
|
+
if (!Object.keys(parentComponent).length && Object.keys(zonParent).length) {
|
|
2038
|
+
parentComponent = zonParent;
|
|
2039
|
+
}
|
|
2040
|
+
if (unresolvedCount && DEBUG_MODE) {
|
|
2041
|
+
console.log(
|
|
2042
|
+
`${unresolvedCount} Zig package hash(es) could not be resolved — dependency graph may be partial.`,
|
|
2043
|
+
);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
if (pkgList.length || Object.keys(parentComponent).length) {
|
|
2048
|
+
return buildBomNSData(options, pkgList, "zig", {
|
|
2049
|
+
src: path,
|
|
2050
|
+
filename: zonFiles.join(", "),
|
|
2051
|
+
parentComponent,
|
|
2052
|
+
dependencies,
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
return {};
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
/**
|
|
2060
|
+
* Function to create bom string for Gleam projects.
|
|
2061
|
+
*
|
|
2062
|
+
* Gleam resolves through Hex, so packages carry `pkg:hex/...` purls and no new
|
|
2063
|
+
* purl type is introduced. The `manifest.toml` lock is the source of truth for
|
|
2064
|
+
* resolved versions and the direct/transitive distinction; `gleam.toml` is the
|
|
2065
|
+
* manifest.
|
|
2066
|
+
*
|
|
2067
|
+
* @param {string} path to the project
|
|
2068
|
+
* @param {Object} options Parse options from the cli
|
|
2069
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
2070
|
+
*/
|
|
2071
|
+
export async function createGleamBom(path, options) {
|
|
2072
|
+
let pkgList = [];
|
|
2073
|
+
let dependencies = [];
|
|
2074
|
+
let parentComponent = {};
|
|
2075
|
+
|
|
2076
|
+
const gleamTomlFiles = getAllFiles(
|
|
2077
|
+
path,
|
|
2078
|
+
`${options.multiProject ? "**/" : ""}gleam.toml`,
|
|
2079
|
+
options,
|
|
2080
|
+
);
|
|
2081
|
+
|
|
2082
|
+
for (const gleamTomlFile of gleamTomlFiles) {
|
|
2083
|
+
if (DEBUG_MODE) {
|
|
2084
|
+
console.log(`Parsing ${gleamTomlFile}`);
|
|
2085
|
+
}
|
|
2086
|
+
const baseDir = dirname(gleamTomlFile);
|
|
2087
|
+
const manifestTomlFile = join(baseDir, "manifest.toml");
|
|
2088
|
+
const lockPath = safeExistsSync(manifestTomlFile)
|
|
2089
|
+
? manifestTomlFile
|
|
2090
|
+
: undefined;
|
|
2091
|
+
const result = parseGleamProject(gleamTomlFile, lockPath);
|
|
2092
|
+
if (result.pkgList?.length) {
|
|
2093
|
+
pkgList = pkgList.concat(result.pkgList);
|
|
2094
|
+
}
|
|
2095
|
+
if (result.dependencies?.length) {
|
|
2096
|
+
dependencies = dependencies.concat(result.dependencies);
|
|
2097
|
+
}
|
|
2098
|
+
if (
|
|
2099
|
+
!Object.keys(parentComponent).length &&
|
|
2100
|
+
Object.keys(result.parentComponent).length
|
|
2101
|
+
) {
|
|
2102
|
+
parentComponent = result.parentComponent;
|
|
2103
|
+
// Attach the root dependency edge to the real parent bom-ref.
|
|
2104
|
+
if (result.rootInputs?.length && parentComponent.name) {
|
|
2105
|
+
const rootRef = `application:${parentComponent.name}:${parentComponent.version || "latest"}`;
|
|
2106
|
+
parentComponent["bom-ref"] = rootRef;
|
|
2107
|
+
dependencies.push({
|
|
2108
|
+
ref: rootRef,
|
|
2109
|
+
dependsOn: [...new Set(result.rootInputs)],
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
if (pkgList.length || Object.keys(parentComponent).length) {
|
|
2116
|
+
return buildBomNSData(options, pkgList, "gleam", {
|
|
2117
|
+
src: path,
|
|
2118
|
+
filename: gleamTomlFiles.join(", "),
|
|
2119
|
+
dependencies,
|
|
2120
|
+
parentComponent,
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
return {};
|
|
2125
|
+
}
|