@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,2083 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { platform as _platform } from "node:os";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
|
|
6
|
+
import { build } from "@cdxgen/cdx-purl";
|
|
7
|
+
|
|
8
|
+
import { DEBUG_MODE, readEnvironmentVariable } from "../core/activity.js";
|
|
9
|
+
import {
|
|
10
|
+
DOTNET_CMD,
|
|
11
|
+
hasAnyProjectType,
|
|
12
|
+
isFeatureEnabled,
|
|
13
|
+
shouldFetchLicense,
|
|
14
|
+
} from "../core/env.js";
|
|
15
|
+
import {
|
|
16
|
+
checksumFile,
|
|
17
|
+
getAllFiles,
|
|
18
|
+
getTmpDir,
|
|
19
|
+
safeExistsSync,
|
|
20
|
+
safeMkdtempSync,
|
|
21
|
+
safeRmSync,
|
|
22
|
+
safeSpawnSync,
|
|
23
|
+
safeWriteSync,
|
|
24
|
+
} from "../core/fs.js";
|
|
25
|
+
import { thoughtLog } from "../core/logger.js";
|
|
26
|
+
import { mapWithConcurrency } from "../core/parallel.js";
|
|
27
|
+
import {
|
|
28
|
+
extractJarArchive,
|
|
29
|
+
getNugetMetadata,
|
|
30
|
+
getPyMetadata,
|
|
31
|
+
parseBdistMetadata,
|
|
32
|
+
} from "../ecosystems/ecosystems.js";
|
|
33
|
+
import {
|
|
34
|
+
getCentralPackageVersions,
|
|
35
|
+
getPropertyGroupTextNodes,
|
|
36
|
+
parseCsPkgData,
|
|
37
|
+
parseCsPkgLockData,
|
|
38
|
+
parseCsProjAssetsData,
|
|
39
|
+
parseCsProjData,
|
|
40
|
+
parseNupkg,
|
|
41
|
+
parsePaketLockData,
|
|
42
|
+
} from "../ecosystems/parsers-dotnet.js";
|
|
43
|
+
import { parseMinJs } from "../ecosystems/parsers-js.js";
|
|
44
|
+
import {
|
|
45
|
+
parseCloudBuildData,
|
|
46
|
+
parseComposerJson,
|
|
47
|
+
parseComposerLock,
|
|
48
|
+
parseGitHubWorkflowData,
|
|
49
|
+
parseHelmYamlData,
|
|
50
|
+
} from "../ecosystems/parsers-misc.js";
|
|
51
|
+
import {
|
|
52
|
+
generatePixiLockFile,
|
|
53
|
+
parseMojoProject,
|
|
54
|
+
parsePiplockData,
|
|
55
|
+
parsePixiLockFile,
|
|
56
|
+
parsePixiTomlFile,
|
|
57
|
+
parsePyLockData,
|
|
58
|
+
parsePyProjectTomlFile,
|
|
59
|
+
parseReqFile,
|
|
60
|
+
parseSetupPyFile,
|
|
61
|
+
} from "../ecosystems/parsers-python.js";
|
|
62
|
+
import { collectEmbeddedSboms } from "../ecosystems/pep770.js";
|
|
63
|
+
import { isPyLockFile } from "../ecosystems/pylockutils.js";
|
|
64
|
+
import {
|
|
65
|
+
createUVLock,
|
|
66
|
+
getPipFrozenTree,
|
|
67
|
+
getPipTreeForPackages,
|
|
68
|
+
getPyModules,
|
|
69
|
+
} from "../ecosystems/pythonutils.js";
|
|
70
|
+
import {
|
|
71
|
+
collectGemModuleNames,
|
|
72
|
+
enrichGemsFromLocalCache,
|
|
73
|
+
parseBundleConfig,
|
|
74
|
+
parseGemfileLockData,
|
|
75
|
+
parseGemspecData,
|
|
76
|
+
} from "../ecosystems/rubyutils.js";
|
|
77
|
+
import {
|
|
78
|
+
collectAiInventory,
|
|
79
|
+
summarizeAiInventory,
|
|
80
|
+
} from "../inventory/aiInventory.js";
|
|
81
|
+
import { detectPythonMcpInventory } from "../inventory/analyzer.js";
|
|
82
|
+
import { isCycloneDxComponentTypeEnabled } from "../inventory/bomUtils.js";
|
|
83
|
+
import {
|
|
84
|
+
collectDosaiCryptoComponents,
|
|
85
|
+
collectSourceCryptoComponents,
|
|
86
|
+
} from "../inventory/cbomutils.js";
|
|
87
|
+
import { readZipEntry } from "../inventory/deps.js";
|
|
88
|
+
import {
|
|
89
|
+
filterInvalidCryptoComponents,
|
|
90
|
+
isPartialTree,
|
|
91
|
+
mergeDependencies,
|
|
92
|
+
mergeServices,
|
|
93
|
+
recomputeScope,
|
|
94
|
+
trimComponents,
|
|
95
|
+
} from "../inventory/depsUtils.js";
|
|
96
|
+
import {
|
|
97
|
+
collectDosaiServicesFromMethods,
|
|
98
|
+
createDosaiMethodsSlice,
|
|
99
|
+
isDosaiDotnetLanguage,
|
|
100
|
+
normalizeDosaiServiceMap,
|
|
101
|
+
readDosaiJsonFile,
|
|
102
|
+
} from "../inventory/dosai.js";
|
|
103
|
+
import { addEvidenceForDotnet } from "../inventory/evidenceUtils.js";
|
|
104
|
+
import { nugetPurl, pypiBomRef } from "../inventory/purl.js";
|
|
105
|
+
import { getPluginToolComponents } from "../managers/binary.js";
|
|
106
|
+
import { getTreeWithPlugin } from "../managers/piptree.js";
|
|
107
|
+
import {
|
|
108
|
+
buildBomNSData,
|
|
109
|
+
createBinaryBom,
|
|
110
|
+
createDefaultParentComponent,
|
|
111
|
+
emitAiInventorySummary,
|
|
112
|
+
getIncludedAiInventoryTypes,
|
|
113
|
+
shouldIncludeNodeModulesDir,
|
|
114
|
+
} from "./bomAssembly.js";
|
|
115
|
+
|
|
116
|
+
const isWin = _platform() === "win32";
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Checks whether a directory contains .NET project or solution files
|
|
120
|
+
* (`*.csproj`, `*.fsproj`, `*.vbproj`, `*.sln`).
|
|
121
|
+
*
|
|
122
|
+
* @param {string} src Directory to inspect
|
|
123
|
+
* @param {object} [options={}] CLI options
|
|
124
|
+
* @returns {boolean} True when at least one .NET project/solution file exists
|
|
125
|
+
*/
|
|
126
|
+
export const hasDotnetProjectIndicators = (src, options = {}) => {
|
|
127
|
+
return Boolean(
|
|
128
|
+
getAllFiles(src, "**/*.{csproj,fsproj,vbproj,sln}", options)?.length,
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Decides whether dosai crypto collection should run for a .NET source. Returns
|
|
134
|
+
* true when an explicit dosai .NET project type is selected, or when no project
|
|
135
|
+
* type (or `universal`) is selected and .NET project indicators are present.
|
|
136
|
+
*
|
|
137
|
+
* @param {string} src Directory to inspect
|
|
138
|
+
* @param {object} [options={}] CLI options
|
|
139
|
+
* @returns {boolean} True when dosai crypto collection should run
|
|
140
|
+
*/
|
|
141
|
+
export const shouldCollectDosaiCrypto = (src, options = {}) => {
|
|
142
|
+
const projectTypes = Array.isArray(options.projectType)
|
|
143
|
+
? options.projectType
|
|
144
|
+
: options.projectType
|
|
145
|
+
? [options.projectType]
|
|
146
|
+
: [];
|
|
147
|
+
if (projectTypes.some((projectType) => isDosaiDotnetLanguage(projectType))) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
if (!projectTypes.length || projectTypes.includes("universal")) {
|
|
151
|
+
return hasDotnetProjectIndicators(src, options);
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Function to create bom string for Projects that use Pixi package manager.
|
|
158
|
+
* createPixiBom is based on createPythonBom.
|
|
159
|
+
* Pixi package manager utilizes many languages like python, rust, C/C++, ruby, etc.
|
|
160
|
+
* It produces a Lockfile which help produce reproducible envs across operating systems.
|
|
161
|
+
* This code will look at the operating system of our machine and create a BOM specific to that machine.
|
|
162
|
+
*
|
|
163
|
+
*
|
|
164
|
+
* @param {String} path
|
|
165
|
+
* @param {Object} options
|
|
166
|
+
* @returns {Object | null} BOM object, or `null` when `pixi.lock` is absent and `options.installDeps` is false
|
|
167
|
+
*/
|
|
168
|
+
export function createPixiBom(path, options) {
|
|
169
|
+
const allImports = {};
|
|
170
|
+
let metadataFilename = "";
|
|
171
|
+
let dependencies = [];
|
|
172
|
+
let pkgList = [];
|
|
173
|
+
let formulationList = [];
|
|
174
|
+
let parentComponent = createDefaultParentComponent(path, "pypi", options);
|
|
175
|
+
let PixiLockData = {};
|
|
176
|
+
|
|
177
|
+
const pixiToml = join(path, "pixi.toml");
|
|
178
|
+
|
|
179
|
+
// if pixi.toml file found then we
|
|
180
|
+
// Add parentComponent Details
|
|
181
|
+
const pixiTomlMode = safeExistsSync(pixiToml);
|
|
182
|
+
if (pixiTomlMode) {
|
|
183
|
+
parentComponent = parsePixiTomlFile(pixiToml);
|
|
184
|
+
parentComponent.type = "application";
|
|
185
|
+
const ppurl = build({
|
|
186
|
+
type: "pypi",
|
|
187
|
+
namespace: parentComponent.group || "" || null,
|
|
188
|
+
name: parentComponent.name,
|
|
189
|
+
version: parentComponent.version || "latest" || null,
|
|
190
|
+
});
|
|
191
|
+
parentComponent["bom-ref"] = decodeURIComponent(ppurl);
|
|
192
|
+
parentComponent["purl"] = ppurl;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const pixiLockFile = join(path, "pixi.lock");
|
|
196
|
+
const pixiFilesMode = safeExistsSync(pixiLockFile);
|
|
197
|
+
if (pixiFilesMode) {
|
|
198
|
+
// Instead of what we do in createPythonBOM
|
|
199
|
+
// where we install packages and run `getPipFrozenTree`
|
|
200
|
+
// here I assume `pixi.lock` file to contain the accuracte version information
|
|
201
|
+
// across all platforms
|
|
202
|
+
PixiLockData = parsePixiLockFile(pixiLockFile, path);
|
|
203
|
+
metadataFilename = "pixi.lock";
|
|
204
|
+
} else {
|
|
205
|
+
if (options.installDeps) {
|
|
206
|
+
generatePixiLockFile(path);
|
|
207
|
+
|
|
208
|
+
const pixiLockFile = join(path, "pixi.lock");
|
|
209
|
+
if (!safeExistsSync(pixiLockFile) && DEBUG_MODE) {
|
|
210
|
+
console.log(
|
|
211
|
+
"Unexpected Error tried to generate pixi.lock file but failed.",
|
|
212
|
+
);
|
|
213
|
+
console.log("This will result in creations of empty BOM.");
|
|
214
|
+
}
|
|
215
|
+
PixiLockData = parsePixiLockFile(pixiLockFile);
|
|
216
|
+
metadataFilename = "pixi.lock";
|
|
217
|
+
} else {
|
|
218
|
+
// If no pixi.lock and installDeps is false
|
|
219
|
+
// then return None and let `createPythonBOM()` handle generation of BOM.
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
pkgList = PixiLockData.pkgList;
|
|
225
|
+
formulationList = PixiLockData.formulationList;
|
|
226
|
+
dependencies = PixiLockData.dependencies;
|
|
227
|
+
|
|
228
|
+
return buildBomNSData(options, pkgList, "pypi", {
|
|
229
|
+
allImports,
|
|
230
|
+
src: path,
|
|
231
|
+
filename: metadataFilename,
|
|
232
|
+
dependencies,
|
|
233
|
+
parentComponent,
|
|
234
|
+
formulationList,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Function to create bom string for Python projects
|
|
240
|
+
*
|
|
241
|
+
* @param {string} path to the project
|
|
242
|
+
* @param {Object} options Parse options from the cli
|
|
243
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
244
|
+
*/
|
|
245
|
+
export async function createPythonBom(path, options) {
|
|
246
|
+
let allImports = {};
|
|
247
|
+
let metadataFilename = "";
|
|
248
|
+
let dependencies = [];
|
|
249
|
+
let pkgList = [];
|
|
250
|
+
let formulationList = [];
|
|
251
|
+
let embeddedSbomCitations = [];
|
|
252
|
+
const includedAiInventoryTypes = getIncludedAiInventoryTypes(options);
|
|
253
|
+
let aiInventory = { components: [], dependencies: [], services: [] };
|
|
254
|
+
let mcpInventory = { components: [], dependencies: [], services: [] };
|
|
255
|
+
const tempDir = safeMkdtempSync(join(getTmpDir(), "cdxgen-venv-"));
|
|
256
|
+
let parentComponent = createDefaultParentComponent(path, "pypi", options);
|
|
257
|
+
// We are checking only the root here for pipenv
|
|
258
|
+
const pipenvMode = safeExistsSync(join(path, "Pipfile"));
|
|
259
|
+
|
|
260
|
+
// If pixi is used then just return that as output instead
|
|
261
|
+
const pixiLockFile = join(path, "pixi.lock");
|
|
262
|
+
const pixiFilesMode = safeExistsSync(pixiLockFile);
|
|
263
|
+
const pixiToml = join(path, "pixi.toml");
|
|
264
|
+
const pixiTomlMode = safeExistsSync(pixiToml);
|
|
265
|
+
// Mojo projects are pixi-managed and carry a `mojoproject.toml` manifest.
|
|
266
|
+
// Its Mojo-specific dependencies use the unregistered `mojo` type, so they
|
|
267
|
+
// are emitted as generic with a proposedType marker; conda/PyPI deps pulled
|
|
268
|
+
// through pixi.lock keep their correct types via the pixi path.
|
|
269
|
+
const mojoProjectFile = join(path, "mojoproject.toml");
|
|
270
|
+
const mojoMode = safeExistsSync(mojoProjectFile);
|
|
271
|
+
let mojoPackages = [];
|
|
272
|
+
let mojoParent = {};
|
|
273
|
+
if (mojoMode) {
|
|
274
|
+
const mojoResult = parseMojoProject(mojoProjectFile);
|
|
275
|
+
mojoPackages = mojoResult.pkgList || [];
|
|
276
|
+
if (mojoResult.parentComponent?.name) {
|
|
277
|
+
mojoParent = mojoResult.parentComponent;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (pixiTomlMode || pixiFilesMode) {
|
|
281
|
+
const BomNSData = createPixiBom(path, options);
|
|
282
|
+
if (BomNSData) {
|
|
283
|
+
// Merge Mojo's own packages into the pixi-derived component list.
|
|
284
|
+
if (mojoPackages.length) {
|
|
285
|
+
const existing = BomNSData.bomJson?.components || [];
|
|
286
|
+
BomNSData.bomJson.components = existing.concat(mojoPackages);
|
|
287
|
+
}
|
|
288
|
+
return BomNSData;
|
|
289
|
+
}
|
|
290
|
+
} else if (mojoMode) {
|
|
291
|
+
// A mojoproject.toml without pixi.lock: emit the Mojo manifest packages.
|
|
292
|
+
if (mojoParent.name) {
|
|
293
|
+
parentComponent = mojoParent;
|
|
294
|
+
}
|
|
295
|
+
pkgList = pkgList.concat(mojoPackages);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
let poetryFiles = getAllFiles(
|
|
299
|
+
path,
|
|
300
|
+
`${options.multiProject ? "**/" : ""}poetry.lock`,
|
|
301
|
+
options,
|
|
302
|
+
);
|
|
303
|
+
const pdmLockFiles = getAllFiles(
|
|
304
|
+
path,
|
|
305
|
+
`${options.multiProject ? "**/" : ""}pdm.lock`,
|
|
306
|
+
options,
|
|
307
|
+
);
|
|
308
|
+
if (pdmLockFiles?.length) {
|
|
309
|
+
poetryFiles = poetryFiles.concat(pdmLockFiles);
|
|
310
|
+
}
|
|
311
|
+
let uvLockFiles = getAllFiles(
|
|
312
|
+
path,
|
|
313
|
+
`${options.multiProject ? "**/" : ""}uv.lock`,
|
|
314
|
+
options,
|
|
315
|
+
);
|
|
316
|
+
if (uvLockFiles?.length) {
|
|
317
|
+
poetryFiles = poetryFiles.concat(uvLockFiles);
|
|
318
|
+
}
|
|
319
|
+
const pyLockFiles = getAllFiles(
|
|
320
|
+
path,
|
|
321
|
+
`${options.multiProject ? "**/" : ""}pylock*.toml`,
|
|
322
|
+
options,
|
|
323
|
+
)?.filter((f) => isPyLockFile(f));
|
|
324
|
+
if (pyLockFiles?.length) {
|
|
325
|
+
poetryFiles = poetryFiles.concat(pyLockFiles);
|
|
326
|
+
}
|
|
327
|
+
let reqFiles = getAllFiles(
|
|
328
|
+
path,
|
|
329
|
+
`${options.multiProject ? "**/" : ""}*requirements*.txt`,
|
|
330
|
+
options,
|
|
331
|
+
);
|
|
332
|
+
reqFiles = reqFiles.filter(
|
|
333
|
+
(f) => !f.includes(join("mercurial", "helptext", "internals")),
|
|
334
|
+
);
|
|
335
|
+
const reqDirFiles = getAllFiles(
|
|
336
|
+
path,
|
|
337
|
+
`${options.multiProject ? "**/" : ""}requirements/*.txt`,
|
|
338
|
+
options,
|
|
339
|
+
);
|
|
340
|
+
const metadataFiles = getAllFiles(
|
|
341
|
+
path,
|
|
342
|
+
`${options.multiProject ? "**/site-packages/**/" : ""}METADATA`,
|
|
343
|
+
{ ...options, includeDot: true },
|
|
344
|
+
);
|
|
345
|
+
const whlFiles = getAllFiles(
|
|
346
|
+
path,
|
|
347
|
+
`${options.multiProject ? "**/" : ""}*.whl`,
|
|
348
|
+
{ ...options, includeDot: true },
|
|
349
|
+
);
|
|
350
|
+
const eggInfoFiles = getAllFiles(
|
|
351
|
+
path,
|
|
352
|
+
`${options.multiProject ? "**/" : ""}*.egg-info`,
|
|
353
|
+
{ ...options, includeDot: true },
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
// Is this a pyproject based project.
|
|
357
|
+
// TODO: Support nested directories
|
|
358
|
+
const pyProjectFile = join(path, "pyproject.toml");
|
|
359
|
+
const pyProjectMode = safeExistsSync(pyProjectFile);
|
|
360
|
+
if (pyProjectMode) {
|
|
361
|
+
const pyProjMap = parsePyProjectTomlFile(pyProjectFile);
|
|
362
|
+
const tmpParentComponent = pyProjMap.parentComponent;
|
|
363
|
+
if (tmpParentComponent?.name) {
|
|
364
|
+
// Bug fix. Version could be missing in pyproject.toml
|
|
365
|
+
if (!tmpParentComponent.version && parentComponent.version) {
|
|
366
|
+
tmpParentComponent.version = parentComponent.version;
|
|
367
|
+
}
|
|
368
|
+
tmpParentComponent.properties = tmpParentComponent.properties || [];
|
|
369
|
+
tmpParentComponent.properties.push({
|
|
370
|
+
name: "internal:SrcFile",
|
|
371
|
+
value: pyProjectFile,
|
|
372
|
+
});
|
|
373
|
+
parentComponent = tmpParentComponent;
|
|
374
|
+
delete parentComponent.homepage;
|
|
375
|
+
delete parentComponent.repository;
|
|
376
|
+
}
|
|
377
|
+
// Is this a uv project without a lock file?
|
|
378
|
+
if (options.installDeps && pyProjMap.uvMode && !uvLockFiles.length) {
|
|
379
|
+
createUVLock(path, options);
|
|
380
|
+
uvLockFiles = getAllFiles(
|
|
381
|
+
path,
|
|
382
|
+
`${options.multiProject ? "**/" : ""}uv.lock`,
|
|
383
|
+
options,
|
|
384
|
+
);
|
|
385
|
+
if (uvLockFiles?.length) {
|
|
386
|
+
poetryFiles = poetryFiles.concat(uvLockFiles);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// When we identify uv lock files, do not parse requirements files
|
|
391
|
+
const requirementsMode =
|
|
392
|
+
(reqFiles?.length || reqDirFiles?.length) &&
|
|
393
|
+
!uvLockFiles.length &&
|
|
394
|
+
!pyLockFiles?.length;
|
|
395
|
+
const poetryMode = poetryFiles?.length;
|
|
396
|
+
|
|
397
|
+
// TODO: Support for nested directories
|
|
398
|
+
const setupPy = join(path, "setup.py");
|
|
399
|
+
const setupPyMode = safeExistsSync(setupPy);
|
|
400
|
+
// Poetry sets up its own virtual env containing site-packages so
|
|
401
|
+
// we give preference to poetry lock file. Issue# 129
|
|
402
|
+
if (poetryMode) {
|
|
403
|
+
for (const f of poetryFiles) {
|
|
404
|
+
const basePath = dirname(f);
|
|
405
|
+
const lockData = readFileSync(f, { encoding: "utf-8" });
|
|
406
|
+
if (DEBUG_MODE) {
|
|
407
|
+
console.log(`Parsing ${f}`);
|
|
408
|
+
}
|
|
409
|
+
let retMap = await parsePyLockData(lockData, f);
|
|
410
|
+
if (retMap?.workspaceWarningShown) {
|
|
411
|
+
options.failOnError && process.exit(1);
|
|
412
|
+
}
|
|
413
|
+
if (retMap?.pyLockProperties?.length) {
|
|
414
|
+
parentComponent.properties = parentComponent.properties || [];
|
|
415
|
+
parentComponent.properties = parentComponent.properties.concat(
|
|
416
|
+
retMap.pyLockProperties,
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
if (retMap.pkgList?.length) {
|
|
420
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
421
|
+
pkgList = trimComponents(pkgList);
|
|
422
|
+
}
|
|
423
|
+
if (retMap?.parentComponent?.components?.length) {
|
|
424
|
+
if (!parentComponent.components) {
|
|
425
|
+
parentComponent.components = [];
|
|
426
|
+
}
|
|
427
|
+
parentComponent.components = parentComponent.components.concat(
|
|
428
|
+
retMap?.parentComponent?.components,
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
if (retMap.dependenciesList?.length) {
|
|
432
|
+
dependencies = mergeDependencies(
|
|
433
|
+
dependencies,
|
|
434
|
+
retMap.dependenciesList,
|
|
435
|
+
parentComponent,
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
if (
|
|
439
|
+
(options.deep || !dependencies.length) &&
|
|
440
|
+
!f.endsWith("uv.lock") &&
|
|
441
|
+
!isPyLockFile(f)
|
|
442
|
+
) {
|
|
443
|
+
if (options.installDeps) {
|
|
444
|
+
retMap = await getPipFrozenTree(
|
|
445
|
+
basePath,
|
|
446
|
+
f,
|
|
447
|
+
tempDir,
|
|
448
|
+
parentComponent,
|
|
449
|
+
path,
|
|
450
|
+
getTreeWithPlugin,
|
|
451
|
+
);
|
|
452
|
+
if (retMap.pkgList?.length) pkgList = pkgList.concat(retMap.pkgList);
|
|
453
|
+
if (retMap.formulationList?.length)
|
|
454
|
+
formulationList = formulationList.concat(retMap.formulationList);
|
|
455
|
+
if (retMap.dependenciesList)
|
|
456
|
+
dependencies = mergeDependencies(
|
|
457
|
+
dependencies,
|
|
458
|
+
retMap.dependenciesList,
|
|
459
|
+
parentComponent,
|
|
460
|
+
);
|
|
461
|
+
if (retMap.rootList) {
|
|
462
|
+
const parentDependsOn = new Set();
|
|
463
|
+
for (const p of retMap.rootList)
|
|
464
|
+
parentDependsOn.add(pypiBomRef(p.name, p.version));
|
|
465
|
+
dependencies.splice(0, 0, {
|
|
466
|
+
ref: parentComponent["bom-ref"],
|
|
467
|
+
dependsOn: [...parentDependsOn].sort(),
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
let exportedReqs = "";
|
|
472
|
+
if (f.endsWith("poetry.lock")) {
|
|
473
|
+
thoughtLog(
|
|
474
|
+
"Using poetry export as a safe, static alternative to pip install.",
|
|
475
|
+
);
|
|
476
|
+
const expCmd = safeSpawnSync(
|
|
477
|
+
"poetry",
|
|
478
|
+
["export", "-f", "requirements.txt"],
|
|
479
|
+
{ cwd: basePath, shell: false },
|
|
480
|
+
);
|
|
481
|
+
if (expCmd.status === 0 && expCmd.stdout)
|
|
482
|
+
exportedReqs = expCmd.stdout.toString();
|
|
483
|
+
} else if (f.endsWith("pdm.lock")) {
|
|
484
|
+
thoughtLog(
|
|
485
|
+
"Using pdm export as a safe, static alternative to pip install.",
|
|
486
|
+
);
|
|
487
|
+
const expCmd = safeSpawnSync(
|
|
488
|
+
"pdm",
|
|
489
|
+
["export", "-f", "requirements"],
|
|
490
|
+
{ cwd: basePath, shell: false },
|
|
491
|
+
);
|
|
492
|
+
if (expCmd.status === 0 && expCmd.stdout)
|
|
493
|
+
exportedReqs = expCmd.stdout.toString();
|
|
494
|
+
}
|
|
495
|
+
if (exportedReqs) {
|
|
496
|
+
const tmpReqFile = join(
|
|
497
|
+
tempDir,
|
|
498
|
+
`exported-${basename(basePath)}-reqs.txt`,
|
|
499
|
+
);
|
|
500
|
+
safeWriteSync(tmpReqFile, exportedReqs);
|
|
501
|
+
const dlist = await parseReqFile(tmpReqFile, false);
|
|
502
|
+
if (dlist?.length) {
|
|
503
|
+
pkgList = pkgList.concat(dlist);
|
|
504
|
+
const parentDependsOn = new Set();
|
|
505
|
+
for (const p of dlist)
|
|
506
|
+
parentDependsOn.add(pypiBomRef(p.name, p.version));
|
|
507
|
+
dependencies.splice(0, 0, {
|
|
508
|
+
ref: parentComponent["bom-ref"],
|
|
509
|
+
dependsOn: [...parentDependsOn].sort(),
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
options.parentComponent = parentComponent;
|
|
517
|
+
} // poetryMode
|
|
518
|
+
if (metadataFiles?.length) {
|
|
519
|
+
// dist-info directories
|
|
520
|
+
for (const mf of metadataFiles) {
|
|
521
|
+
const dlist = parseBdistMetadata(mf);
|
|
522
|
+
if (dlist?.length) {
|
|
523
|
+
pkgList = pkgList.concat(dlist);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
// .whl files. Zip file containing dist-info directory
|
|
528
|
+
if (whlFiles?.length) {
|
|
529
|
+
for (const wf of whlFiles) {
|
|
530
|
+
const mData = await readZipEntry(wf, "METADATA");
|
|
531
|
+
if (mData) {
|
|
532
|
+
const dlist = parseBdistMetadata(join(wf, "METADATA"), mData);
|
|
533
|
+
if (dlist?.length) {
|
|
534
|
+
pkgList = pkgList.concat(dlist);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
// .egg-info files
|
|
540
|
+
if (eggInfoFiles?.length) {
|
|
541
|
+
for (const ef of eggInfoFiles) {
|
|
542
|
+
const dlist = parseBdistMetadata(ef);
|
|
543
|
+
if (dlist?.length) {
|
|
544
|
+
pkgList = pkgList.concat(dlist);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
// PEP 770: discover SBOMs embedded under `<dist>.dist-info/sboms/` in
|
|
549
|
+
// installed distributions and wheels. An embedded SBOM is stronger than
|
|
550
|
+
// cdxgen's inference, so its components are merged as dependencies *of* the
|
|
551
|
+
// distribution that supplied them. The data is untrusted third-party input,
|
|
552
|
+
// so the collector bounds its size, validates it, and skips anything invalid.
|
|
553
|
+
const embedded = await collectEmbeddedSboms({
|
|
554
|
+
metadataFiles,
|
|
555
|
+
whlFiles,
|
|
556
|
+
});
|
|
557
|
+
if (embedded.components.length) {
|
|
558
|
+
// Embedded components come first so the later trimComponents dedupe keeps
|
|
559
|
+
// them when they conflict with an inferred component: an embedded SBOM is a
|
|
560
|
+
// stronger assertion than cdxgen's inference, and the union records the
|
|
561
|
+
// conflict rather than discarding it.
|
|
562
|
+
pkgList = embedded.components.concat(pkgList);
|
|
563
|
+
}
|
|
564
|
+
if (embedded.dependencies.length) {
|
|
565
|
+
dependencies = mergeDependencies(
|
|
566
|
+
dependencies,
|
|
567
|
+
embedded.dependencies,
|
|
568
|
+
parentComponent,
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
if (embedded.citations.length) {
|
|
572
|
+
embeddedSbomCitations = embedded.citations;
|
|
573
|
+
}
|
|
574
|
+
if (requirementsMode || pipenvMode) {
|
|
575
|
+
if (pipenvMode) {
|
|
576
|
+
// TODO: Support for nested directories
|
|
577
|
+
safeSpawnSync("pipenv", ["install"], { cwd: path, shell: isWin });
|
|
578
|
+
const piplockFile = join(path, "Pipfile.lock");
|
|
579
|
+
if (safeExistsSync(piplockFile)) {
|
|
580
|
+
const lockData = JSON.parse(readFileSync(piplockFile));
|
|
581
|
+
const dlist = await parsePiplockData(lockData);
|
|
582
|
+
if (dlist?.length) {
|
|
583
|
+
pkgList = pkgList.concat(dlist);
|
|
584
|
+
}
|
|
585
|
+
} else {
|
|
586
|
+
console.error("Pipfile.lock not found at", path);
|
|
587
|
+
options.failOnError && process.exit(1);
|
|
588
|
+
}
|
|
589
|
+
} else if (reqDirFiles?.length) {
|
|
590
|
+
for (const j in reqDirFiles) {
|
|
591
|
+
const f = reqDirFiles[j];
|
|
592
|
+
const dlist = await parseReqFile(f, false);
|
|
593
|
+
if (dlist?.length) {
|
|
594
|
+
pkgList = pkgList.concat(dlist);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
metadataFilename = reqDirFiles.join(", ");
|
|
598
|
+
} else if (reqFiles?.length) {
|
|
599
|
+
for (const f of reqFiles) {
|
|
600
|
+
const dlist = await parseReqFile(f, false);
|
|
601
|
+
if (dlist?.length) {
|
|
602
|
+
pkgList = pkgList.concat(dlist);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const parentDependsOn = new Set();
|
|
609
|
+
|
|
610
|
+
// Use atom in requirements, setup.py and pyproject.toml mode
|
|
611
|
+
if (requirementsMode || setupPyMode || pyProjectMode || options.deep) {
|
|
612
|
+
/**
|
|
613
|
+
* The order of preference is pyproject.toml (newer) and then setup.py
|
|
614
|
+
*/
|
|
615
|
+
if (options.installDeps) {
|
|
616
|
+
let pkgMap;
|
|
617
|
+
if (pyProjectMode && !poetryMode) {
|
|
618
|
+
pkgMap = await getPipFrozenTree(
|
|
619
|
+
path,
|
|
620
|
+
pyProjectFile,
|
|
621
|
+
tempDir,
|
|
622
|
+
parentComponent,
|
|
623
|
+
path,
|
|
624
|
+
getTreeWithPlugin,
|
|
625
|
+
);
|
|
626
|
+
} else if (setupPyMode) {
|
|
627
|
+
pkgMap = await getPipFrozenTree(
|
|
628
|
+
path,
|
|
629
|
+
setupPy,
|
|
630
|
+
tempDir,
|
|
631
|
+
parentComponent,
|
|
632
|
+
path,
|
|
633
|
+
getTreeWithPlugin,
|
|
634
|
+
);
|
|
635
|
+
} else if (requirementsMode && reqFiles?.length) {
|
|
636
|
+
if (options.installDeps && DEBUG_MODE) {
|
|
637
|
+
console.log(
|
|
638
|
+
"cdxgen will now attempt to generate an SBOM for 'build' lifecycle phase for Python. This would take some time ...\nTo speed up this step, invoke cdxgen from within a virtual environment with all the dependencies installed.\nAlternatively, pass the argument '--lifecycle pre-build' to generate a faster but less precise SBOM.",
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
for (const f of reqFiles) {
|
|
642
|
+
const basePath = dirname(f);
|
|
643
|
+
if (options.installDeps) {
|
|
644
|
+
const rpkgMap = await getPipFrozenTree(
|
|
645
|
+
basePath,
|
|
646
|
+
f,
|
|
647
|
+
tempDir,
|
|
648
|
+
parentComponent,
|
|
649
|
+
path,
|
|
650
|
+
getTreeWithPlugin,
|
|
651
|
+
);
|
|
652
|
+
if (rpkgMap.pkgList?.length) {
|
|
653
|
+
pkgList = pkgList.concat(rpkgMap.pkgList);
|
|
654
|
+
pkgList = trimComponents(pkgList);
|
|
655
|
+
}
|
|
656
|
+
if (rpkgMap.formulationList?.length) {
|
|
657
|
+
formulationList = formulationList.concat(rpkgMap.formulationList);
|
|
658
|
+
formulationList = trimComponents(formulationList);
|
|
659
|
+
}
|
|
660
|
+
if (rpkgMap.dependenciesList) {
|
|
661
|
+
dependencies = mergeDependencies(
|
|
662
|
+
dependencies,
|
|
663
|
+
rpkgMap.dependenciesList,
|
|
664
|
+
parentComponent,
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
// Add the root packages from this file to the parent's dependencies
|
|
668
|
+
for (const p of rpkgMap.rootList) {
|
|
669
|
+
if (
|
|
670
|
+
parentComponent &&
|
|
671
|
+
p.name === parentComponent.name &&
|
|
672
|
+
(p.version === parentComponent.version ||
|
|
673
|
+
p.version === "latest")
|
|
674
|
+
) {
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
parentDependsOn.add(pypiBomRef(p.name, p.version));
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
} else if (!poetryMode) {
|
|
682
|
+
pkgMap = await getPipFrozenTree(
|
|
683
|
+
path,
|
|
684
|
+
undefined,
|
|
685
|
+
tempDir,
|
|
686
|
+
parentComponent,
|
|
687
|
+
path,
|
|
688
|
+
getTreeWithPlugin,
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
if (pkgMap) {
|
|
692
|
+
// Complete the dependency tree by making parent component depend on the first level
|
|
693
|
+
for (const p of pkgMap.rootList) {
|
|
694
|
+
if (
|
|
695
|
+
parentComponent &&
|
|
696
|
+
p.name === parentComponent.name &&
|
|
697
|
+
(p.version === parentComponent.version || p.version === "latest")
|
|
698
|
+
) {
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
parentDependsOn.add(pypiBomRef(p.name, p.version));
|
|
702
|
+
}
|
|
703
|
+
if (pkgMap?.pkgList?.length) {
|
|
704
|
+
pkgList = pkgList.concat(pkgMap.pkgList);
|
|
705
|
+
}
|
|
706
|
+
if (pkgMap?.formulationList?.length) {
|
|
707
|
+
formulationList = formulationList.concat(pkgMap.formulationList);
|
|
708
|
+
}
|
|
709
|
+
if (pkgMap?.dependenciesList) {
|
|
710
|
+
dependencies = mergeDependencies(
|
|
711
|
+
dependencies,
|
|
712
|
+
pkgMap.dependenciesList,
|
|
713
|
+
parentComponent,
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
// ATOM parsedeps block
|
|
718
|
+
// Atom parsedeps slices can be used to identify packages that are not declared in manifests
|
|
719
|
+
// Since it is a slow operation, we only use it as a fallback or in deep mode
|
|
720
|
+
// This change was made in 10.9.2 release onwards
|
|
721
|
+
if (options.deep || !pkgList.length) {
|
|
722
|
+
if (!pkgList.length) {
|
|
723
|
+
thoughtLog(
|
|
724
|
+
"I couldn't find any components yet. Let's try static analysis with atom parsedeps command.",
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
const retMap = await getPyModules(path, pkgList, options);
|
|
728
|
+
// We need to patch the existing package list to add ImportedModules for evinse to work
|
|
729
|
+
if (retMap.modList?.length) {
|
|
730
|
+
const iSymbolsMap = {};
|
|
731
|
+
retMap.modList.forEach((v) => {
|
|
732
|
+
iSymbolsMap[v.name] = v.importedSymbols;
|
|
733
|
+
iSymbolsMap[v.name.replace(/_/g, "-")] = v.importedSymbols;
|
|
734
|
+
});
|
|
735
|
+
for (const apkg of pkgList) {
|
|
736
|
+
if (iSymbolsMap[apkg.name]) {
|
|
737
|
+
apkg.scope = "required";
|
|
738
|
+
apkg.properties = apkg.properties || [];
|
|
739
|
+
apkg.properties.push({
|
|
740
|
+
name: "internal:ImportedModules",
|
|
741
|
+
value: iSymbolsMap[apkg.name],
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (retMap.pkgList?.length) {
|
|
747
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
748
|
+
for (const p of retMap.pkgList) {
|
|
749
|
+
if (
|
|
750
|
+
!p.version ||
|
|
751
|
+
(parentComponent &&
|
|
752
|
+
p.name === parentComponent.name &&
|
|
753
|
+
(p.version === parentComponent.version ||
|
|
754
|
+
p.version === "latest"))
|
|
755
|
+
) {
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
parentDependsOn.add(pypiBomRef(p.name, p.version));
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (retMap.dependenciesList) {
|
|
762
|
+
dependencies = mergeDependencies(
|
|
763
|
+
dependencies,
|
|
764
|
+
retMap.dependenciesList,
|
|
765
|
+
parentComponent,
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
if (retMap.allImports) {
|
|
769
|
+
allImports = { ...allImports, ...retMap.allImports };
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
// ATOM parsedeps block
|
|
773
|
+
let parentPresent = false;
|
|
774
|
+
for (const d of dependencies) {
|
|
775
|
+
if (d.ref === parentComponent["bom-ref"]) {
|
|
776
|
+
parentPresent = true;
|
|
777
|
+
break;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
if (!parentPresent) {
|
|
781
|
+
const pdependencies = {
|
|
782
|
+
ref: parentComponent["bom-ref"],
|
|
783
|
+
dependsOn: Array.from(parentDependsOn).filter(
|
|
784
|
+
(r) => parentComponent && r !== parentComponent["bom-ref"],
|
|
785
|
+
),
|
|
786
|
+
};
|
|
787
|
+
dependencies.splice(0, 0, pdependencies);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
// Final fallback is to manually parse setup.py if we still
|
|
792
|
+
// have an empty list
|
|
793
|
+
if (!pkgList.length && setupPyMode) {
|
|
794
|
+
const setupPyData = readFileSync(setupPy, { encoding: "utf-8" });
|
|
795
|
+
const dlist = await parseSetupPyFile(setupPyData);
|
|
796
|
+
if (dlist?.length) {
|
|
797
|
+
pkgList = pkgList.concat(dlist);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
if (includedAiInventoryTypes.length) {
|
|
801
|
+
aiInventory = collectAiInventory(path, options, includedAiInventoryTypes);
|
|
802
|
+
if (includedAiInventoryTypes.includes("mcp")) {
|
|
803
|
+
mcpInventory = detectPythonMcpInventory(path, options.deep);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
const aiInventorySummary = summarizeAiInventory(aiInventory);
|
|
807
|
+
if (aiInventorySummary.instructionCount || aiInventorySummary.skillCount) {
|
|
808
|
+
thoughtLog(
|
|
809
|
+
`I found ${aiInventorySummary.instructionCount + aiInventorySummary.skillCount} AI skill/instruction file component(s). Use '--exclude-type ai-skill' for a package-only BOM, or '--bom-audit --bom-audit-categories ai-inventory' for review-friendly reporting.`,
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
if (aiInventorySummary.mcpConfigCount) {
|
|
813
|
+
thoughtLog(
|
|
814
|
+
`I found ${aiInventorySummary.mcpConfigCount} MCP config component(s). Use '--exclude-type mcp' to drop them, or '--bom-audit --bom-audit-categories ai-inventory --tlp-classification AMBER' to keep and flag them.`,
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
emitAiInventorySummary(aiInventory, path);
|
|
818
|
+
// Check and complete the dependency tree
|
|
819
|
+
if (
|
|
820
|
+
isFeatureEnabled(options, "safe-pip-install") &&
|
|
821
|
+
pkgList.length &&
|
|
822
|
+
isPartialTree(dependencies, pkgList.length)
|
|
823
|
+
) {
|
|
824
|
+
// Trim the current package list first
|
|
825
|
+
pkgList = trimComponents(pkgList);
|
|
826
|
+
console.log(
|
|
827
|
+
`Attempting to recover the pip dependency tree from ${pkgList.length} packages. Please wait ...`,
|
|
828
|
+
);
|
|
829
|
+
const newPkgMap = getPipTreeForPackages(
|
|
830
|
+
path,
|
|
831
|
+
pkgList,
|
|
832
|
+
tempDir,
|
|
833
|
+
parentComponent,
|
|
834
|
+
getTreeWithPlugin,
|
|
835
|
+
);
|
|
836
|
+
if (DEBUG_MODE && newPkgMap?.failedPkgList?.length) {
|
|
837
|
+
if (newPkgMap.failedPkgList.length < pkgList.length) {
|
|
838
|
+
console.log(
|
|
839
|
+
`${newPkgMap.failedPkgList.length} packages failed to install.`,
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
if (newPkgMap?.pkgList?.length) {
|
|
844
|
+
pkgList = pkgList.concat(newPkgMap.pkgList);
|
|
845
|
+
pkgList = trimComponents(pkgList);
|
|
846
|
+
}
|
|
847
|
+
if (newPkgMap.dependenciesList) {
|
|
848
|
+
dependencies = mergeDependencies(
|
|
849
|
+
dependencies,
|
|
850
|
+
newPkgMap.dependenciesList,
|
|
851
|
+
parentComponent,
|
|
852
|
+
);
|
|
853
|
+
if (DEBUG_MODE && dependencies.length > 1) {
|
|
854
|
+
console.log("Recovered", dependencies.length, "dependencies.");
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
// Clean up
|
|
859
|
+
if (tempDir?.startsWith(getTmpDir())) {
|
|
860
|
+
safeRmSync(tempDir, { recursive: true, force: true });
|
|
861
|
+
}
|
|
862
|
+
// Re-compute the component scope
|
|
863
|
+
pkgList = recomputeScope(pkgList, dependencies);
|
|
864
|
+
if (shouldFetchLicense()) {
|
|
865
|
+
pkgList = await getPyMetadata(pkgList, false);
|
|
866
|
+
}
|
|
867
|
+
if (mcpInventory.components?.length) {
|
|
868
|
+
pkgList = trimComponents(pkgList.concat(mcpInventory.components));
|
|
869
|
+
}
|
|
870
|
+
if (mcpInventory.dependencies?.length) {
|
|
871
|
+
dependencies = mergeDependencies(
|
|
872
|
+
dependencies,
|
|
873
|
+
mcpInventory.dependencies,
|
|
874
|
+
parentComponent,
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
if (aiInventory.components?.length) {
|
|
878
|
+
pkgList = trimComponents(pkgList.concat(aiInventory.components));
|
|
879
|
+
}
|
|
880
|
+
if (aiInventory.dependencies?.length) {
|
|
881
|
+
dependencies = mergeDependencies(
|
|
882
|
+
dependencies,
|
|
883
|
+
aiInventory.dependencies,
|
|
884
|
+
parentComponent,
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
const inventoryServices = mergeServices(
|
|
888
|
+
mergeServices([], mcpInventory.services || []),
|
|
889
|
+
aiInventory.services || [],
|
|
890
|
+
);
|
|
891
|
+
return buildBomNSData(options, pkgList, "pypi", {
|
|
892
|
+
allImports,
|
|
893
|
+
src: path,
|
|
894
|
+
filename: metadataFilename,
|
|
895
|
+
dependencies,
|
|
896
|
+
parentComponent,
|
|
897
|
+
formulationList,
|
|
898
|
+
citations: embeddedSbomCitations,
|
|
899
|
+
services: inventoryServices,
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Function to create bom string for GitHub action workflows
|
|
905
|
+
*
|
|
906
|
+
* @param {string} path to the project
|
|
907
|
+
* @param {Object} options Parse options from the cli
|
|
908
|
+
* @returns {Object} BOM object
|
|
909
|
+
*/
|
|
910
|
+
export function createGitHubBom(path, options) {
|
|
911
|
+
const ghactionFiles = getAllFiles(
|
|
912
|
+
path,
|
|
913
|
+
".github/workflows/" + "*.{yml,yaml}",
|
|
914
|
+
options,
|
|
915
|
+
);
|
|
916
|
+
let pkgList = [];
|
|
917
|
+
if (ghactionFiles.length) {
|
|
918
|
+
for (const f of ghactionFiles) {
|
|
919
|
+
if (DEBUG_MODE) {
|
|
920
|
+
console.log(`Parsing ${f}`);
|
|
921
|
+
}
|
|
922
|
+
const dlist = parseGitHubWorkflowData(f);
|
|
923
|
+
if (dlist?.length) {
|
|
924
|
+
pkgList = pkgList.concat(dlist);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
return buildBomNSData(options, pkgList, "github", {
|
|
928
|
+
src: path,
|
|
929
|
+
filename: ghactionFiles.join(", "),
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
return {};
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Function to create bom string for cloudbuild yaml
|
|
937
|
+
*
|
|
938
|
+
* @param {string} path to the project
|
|
939
|
+
* @param {Object} options Parse options from the cli
|
|
940
|
+
* @returns {Object} BOM object
|
|
941
|
+
*/
|
|
942
|
+
export function createCloudBuildBom(path, options) {
|
|
943
|
+
const cbFiles = getAllFiles(path, "cloudbuild.yml", options);
|
|
944
|
+
let pkgList = [];
|
|
945
|
+
if (cbFiles.length) {
|
|
946
|
+
for (const f of cbFiles) {
|
|
947
|
+
if (DEBUG_MODE) {
|
|
948
|
+
console.log(`Parsing ${f}`);
|
|
949
|
+
}
|
|
950
|
+
const cbwData = readFileSync(f, { encoding: "utf-8" });
|
|
951
|
+
const dlist = parseCloudBuildData(cbwData);
|
|
952
|
+
if (dlist?.length) {
|
|
953
|
+
pkgList = pkgList.concat(dlist);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return buildBomNSData(options, pkgList, "cloudbuild", {
|
|
957
|
+
src: path,
|
|
958
|
+
filename: cbFiles.join(", "),
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
return {};
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Function to create bom string for Jenkins plugins
|
|
966
|
+
*
|
|
967
|
+
* @param {string} path to the project
|
|
968
|
+
* @param {Object} options Parse options from the cli
|
|
969
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
970
|
+
*/
|
|
971
|
+
export async function createJenkinsBom(path, options) {
|
|
972
|
+
let pkgList = [];
|
|
973
|
+
const hpiFiles = getAllFiles(
|
|
974
|
+
path,
|
|
975
|
+
`${options.multiProject ? "**/" : ""}*.hpi`,
|
|
976
|
+
options,
|
|
977
|
+
);
|
|
978
|
+
const tempDir = safeMkdtempSync(join(getTmpDir(), "hpi-deps-"));
|
|
979
|
+
if (hpiFiles.length) {
|
|
980
|
+
for (const f of hpiFiles) {
|
|
981
|
+
if (DEBUG_MODE) {
|
|
982
|
+
console.log(`Parsing ${f}`);
|
|
983
|
+
}
|
|
984
|
+
const dlist = await extractJarArchive(f, tempDir);
|
|
985
|
+
if (dlist?.length) {
|
|
986
|
+
pkgList = pkgList.concat(dlist);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const jsFiles = getAllFiles(tempDir, "**/*.js", options);
|
|
991
|
+
if (jsFiles.length) {
|
|
992
|
+
for (const f of jsFiles) {
|
|
993
|
+
if (DEBUG_MODE) {
|
|
994
|
+
console.log(`Parsing ${f}`);
|
|
995
|
+
}
|
|
996
|
+
const dlist = await parseMinJs(f);
|
|
997
|
+
if (dlist?.length) {
|
|
998
|
+
pkgList = pkgList.concat(dlist);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
// Clean up
|
|
1003
|
+
if (tempDir?.startsWith(getTmpDir())) {
|
|
1004
|
+
console.log(`Cleaning up ${tempDir}`);
|
|
1005
|
+
safeRmSync(tempDir, { recursive: true, force: true });
|
|
1006
|
+
}
|
|
1007
|
+
return buildBomNSData(options, pkgList, "maven", {
|
|
1008
|
+
src: path,
|
|
1009
|
+
filename: hpiFiles.join(", "),
|
|
1010
|
+
nsMapping: {},
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* Function to create bom string for Helm charts
|
|
1016
|
+
*
|
|
1017
|
+
* @param {string} path to the project
|
|
1018
|
+
* @param {Object} options Parse options from the cli
|
|
1019
|
+
* @returns {Object} BOM object
|
|
1020
|
+
*/
|
|
1021
|
+
export function createHelmBom(path, options) {
|
|
1022
|
+
let pkgList = [];
|
|
1023
|
+
const yamlFiles = getAllFiles(
|
|
1024
|
+
path,
|
|
1025
|
+
`${options.multiProject ? "**/" : ""}*.yaml`,
|
|
1026
|
+
options,
|
|
1027
|
+
);
|
|
1028
|
+
if (yamlFiles.length) {
|
|
1029
|
+
for (const f of yamlFiles) {
|
|
1030
|
+
if (DEBUG_MODE) {
|
|
1031
|
+
console.log(`Parsing ${f}`);
|
|
1032
|
+
}
|
|
1033
|
+
const helmData = readFileSync(f, { encoding: "utf-8" });
|
|
1034
|
+
const dlist = parseHelmYamlData(helmData);
|
|
1035
|
+
if (dlist?.length) {
|
|
1036
|
+
pkgList = pkgList.concat(dlist);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
return buildBomNSData(options, pkgList, "helm", {
|
|
1040
|
+
src: path,
|
|
1041
|
+
filename: yamlFiles.join(", "),
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
return {};
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* Function to create bom string for php projects
|
|
1049
|
+
*
|
|
1050
|
+
* @param {string} path to the project
|
|
1051
|
+
* @param {Object} options Parse options from the cli
|
|
1052
|
+
* @returns {Object} BOM object
|
|
1053
|
+
*/
|
|
1054
|
+
export function createPHPBom(path, options) {
|
|
1055
|
+
let dependencies = [];
|
|
1056
|
+
let parentComponent = {};
|
|
1057
|
+
const searchOptions = {
|
|
1058
|
+
...options,
|
|
1059
|
+
includeNodeModulesDir:
|
|
1060
|
+
typeof options.includeNodeModulesDir === "undefined"
|
|
1061
|
+
? shouldIncludeNodeModulesDir(options, ["php"])
|
|
1062
|
+
: options.includeNodeModulesDir,
|
|
1063
|
+
};
|
|
1064
|
+
const composerLockSearchOptions = {
|
|
1065
|
+
...searchOptions,
|
|
1066
|
+
exclude: [...(options.exclude || []), "**/vendor/**"],
|
|
1067
|
+
};
|
|
1068
|
+
const composerJsonFiles = getAllFiles(
|
|
1069
|
+
path,
|
|
1070
|
+
`${options.multiProject ? "**/" : ""}composer.json`,
|
|
1071
|
+
searchOptions,
|
|
1072
|
+
);
|
|
1073
|
+
let composerLockFiles = getAllFiles(
|
|
1074
|
+
path,
|
|
1075
|
+
`${options.multiProject ? "**/" : ""}composer.lock`,
|
|
1076
|
+
composerLockSearchOptions,
|
|
1077
|
+
);
|
|
1078
|
+
let pkgList = [];
|
|
1079
|
+
const composerJsonMode = composerJsonFiles.length;
|
|
1080
|
+
const composerLockMode = composerLockFiles.length;
|
|
1081
|
+
// Create a composer.lock file for each composer.json file if needed.
|
|
1082
|
+
if (!composerLockMode && composerJsonMode && options.installDeps) {
|
|
1083
|
+
if (DEBUG_MODE) {
|
|
1084
|
+
console.log("About to invoke composer --version");
|
|
1085
|
+
}
|
|
1086
|
+
const versionResult = safeSpawnSync("composer", ["--version"], {
|
|
1087
|
+
shell: isWin,
|
|
1088
|
+
});
|
|
1089
|
+
if (versionResult.status !== 0 || versionResult.error) {
|
|
1090
|
+
console.error(
|
|
1091
|
+
"No composer version found. Check if composer is installed and available in PATH.",
|
|
1092
|
+
);
|
|
1093
|
+
if (DEBUG_MODE) {
|
|
1094
|
+
console.log(versionResult.error, versionResult.stderr);
|
|
1095
|
+
}
|
|
1096
|
+
options.failOnError && process.exit(1);
|
|
1097
|
+
}
|
|
1098
|
+
let composerVersion;
|
|
1099
|
+
if (DEBUG_MODE) {
|
|
1100
|
+
console.log("Parsing version", versionResult.stdout);
|
|
1101
|
+
}
|
|
1102
|
+
let tmpV;
|
|
1103
|
+
if (versionResult?.stdout) {
|
|
1104
|
+
tmpV = versionResult.stdout.split(" ");
|
|
1105
|
+
}
|
|
1106
|
+
if (tmpV && tmpV.length > 1) {
|
|
1107
|
+
composerVersion = tmpV[1];
|
|
1108
|
+
}
|
|
1109
|
+
for (const f of composerJsonFiles) {
|
|
1110
|
+
const basePath = dirname(f);
|
|
1111
|
+
let args = [];
|
|
1112
|
+
if (composerVersion && !composerVersion.startsWith("1")) {
|
|
1113
|
+
console.log("Generating composer.lock in", basePath);
|
|
1114
|
+
args = ["update", "--no-install", "--ignore-platform-reqs"];
|
|
1115
|
+
} else {
|
|
1116
|
+
console.log("Executing 'composer install' in", basePath);
|
|
1117
|
+
args = ["install", "--ignore-platform-reqs"];
|
|
1118
|
+
}
|
|
1119
|
+
const result = safeSpawnSync("composer", args, {
|
|
1120
|
+
cwd: basePath,
|
|
1121
|
+
shell: isWin,
|
|
1122
|
+
});
|
|
1123
|
+
if (result.status !== 0 || result.error) {
|
|
1124
|
+
console.error("Error running composer:");
|
|
1125
|
+
if (result.stdout) {
|
|
1126
|
+
console.log(result.stdout);
|
|
1127
|
+
}
|
|
1128
|
+
if (result.stderr) {
|
|
1129
|
+
console.log(result.stderr);
|
|
1130
|
+
}
|
|
1131
|
+
console.log(result.error);
|
|
1132
|
+
options.failOnError && process.exit(1);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
composerLockFiles = getAllFiles(
|
|
1137
|
+
path,
|
|
1138
|
+
`${options.multiProject ? "**/" : ""}composer.lock`,
|
|
1139
|
+
composerLockSearchOptions,
|
|
1140
|
+
);
|
|
1141
|
+
if (composerLockFiles.length) {
|
|
1142
|
+
// Look for any root composer.json to capture the parentComponent
|
|
1143
|
+
if (safeExistsSync(join(path, "composer.json"))) {
|
|
1144
|
+
const { moduleParent } = parseComposerJson(join(path, "composer.json"));
|
|
1145
|
+
parentComponent = moduleParent;
|
|
1146
|
+
}
|
|
1147
|
+
for (const f of composerLockFiles) {
|
|
1148
|
+
const basePath = dirname(f);
|
|
1149
|
+
let moduleParent;
|
|
1150
|
+
if (DEBUG_MODE) {
|
|
1151
|
+
console.log(`Parsing ${f}`);
|
|
1152
|
+
}
|
|
1153
|
+
let rootRequires = [];
|
|
1154
|
+
// Is there a composer.json to find the module parent component
|
|
1155
|
+
if (safeExistsSync(join(basePath, "composer.json"))) {
|
|
1156
|
+
const retMap = parseComposerJson(join(basePath, "composer.json"));
|
|
1157
|
+
moduleParent = retMap.moduleParent;
|
|
1158
|
+
rootRequires = retMap.rootRequires;
|
|
1159
|
+
// Track all the modules in a mono-repo
|
|
1160
|
+
if (!Object.keys(parentComponent).length) {
|
|
1161
|
+
parentComponent = { ...moduleParent };
|
|
1162
|
+
} else if (moduleParent?.["bom-ref"]) {
|
|
1163
|
+
parentComponent.components = parentComponent.components || [];
|
|
1164
|
+
parentComponent.components.push(moduleParent);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
const retMap = parseComposerLock(f, rootRequires);
|
|
1168
|
+
if (retMap.pkgList?.length) {
|
|
1169
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
1170
|
+
pkgList = trimComponents(pkgList);
|
|
1171
|
+
}
|
|
1172
|
+
if (retMap.dependenciesList) {
|
|
1173
|
+
if (moduleParent?.["bom-ref"]) {
|
|
1174
|
+
// Complete the dependency tree by making parent component depend on the first level
|
|
1175
|
+
dependencies.splice(0, 0, {
|
|
1176
|
+
ref: moduleParent["bom-ref"],
|
|
1177
|
+
dependsOn: [
|
|
1178
|
+
...new Set(
|
|
1179
|
+
retMap.rootList.map((p) => p["bom-ref"]).filter(Boolean),
|
|
1180
|
+
),
|
|
1181
|
+
].sort(),
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
dependencies = mergeDependencies(
|
|
1185
|
+
dependencies,
|
|
1186
|
+
retMap.dependenciesList,
|
|
1187
|
+
parentComponent,
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
// Complete the root dependency tree
|
|
1192
|
+
if (parentComponent?.components?.length) {
|
|
1193
|
+
const parentDependsOn = parentComponent.components
|
|
1194
|
+
.map((d) => d["bom-ref"])
|
|
1195
|
+
.filter(Boolean);
|
|
1196
|
+
dependencies = mergeDependencies(
|
|
1197
|
+
[{ ref: parentComponent["bom-ref"], dependsOn: parentDependsOn }],
|
|
1198
|
+
dependencies,
|
|
1199
|
+
parentComponent,
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
return buildBomNSData(options, pkgList, "composer", {
|
|
1203
|
+
src: path,
|
|
1204
|
+
filename: composerLockFiles.join(", "),
|
|
1205
|
+
dependencies,
|
|
1206
|
+
parentComponent,
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
return {};
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Function to create bom string for ruby projects
|
|
1214
|
+
*
|
|
1215
|
+
* @param {string} path to the project
|
|
1216
|
+
* @param {Object} options Parse options from the cli
|
|
1217
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
1218
|
+
*/
|
|
1219
|
+
export async function createRubyBom(path, options) {
|
|
1220
|
+
// We can look for gem files within node_modules directory
|
|
1221
|
+
if (typeof options.includeNodeModulesDir === "undefined" || options.deep) {
|
|
1222
|
+
options.includeNodeModulesDir = true;
|
|
1223
|
+
}
|
|
1224
|
+
const excludeList = (options.exclude || []).concat(["**/vendor/cache/**"]);
|
|
1225
|
+
const gemLockExcludeList = (options.exclude || []).concat([
|
|
1226
|
+
"**/vendor/bundle/ruby/**/Gemfile.lock",
|
|
1227
|
+
"**/test/data/**/Gemfile*.lock",
|
|
1228
|
+
"**/.rbenv/versions/**/Gemfile.lock",
|
|
1229
|
+
]);
|
|
1230
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1231
|
+
excludeList.push("**/vendor/bundle/**");
|
|
1232
|
+
gemLockExcludeList.push("**/vendor/cache/**");
|
|
1233
|
+
}
|
|
1234
|
+
const gemFiles = getAllFiles(
|
|
1235
|
+
path,
|
|
1236
|
+
`${options.multiProject ? "**/" : ""}Gemfile`,
|
|
1237
|
+
{
|
|
1238
|
+
...options,
|
|
1239
|
+
exclude: excludeList,
|
|
1240
|
+
},
|
|
1241
|
+
);
|
|
1242
|
+
let gemLockFiles = getAllFiles(
|
|
1243
|
+
path,
|
|
1244
|
+
`${options.multiProject ? "**/" : ""}Gemfile*.lock`,
|
|
1245
|
+
{
|
|
1246
|
+
...options,
|
|
1247
|
+
exclude: gemLockExcludeList,
|
|
1248
|
+
},
|
|
1249
|
+
);
|
|
1250
|
+
let gemspecFiles = getAllFiles(
|
|
1251
|
+
path,
|
|
1252
|
+
`${options.multiProject ? "**/" : ""}*.gemspec`,
|
|
1253
|
+
{
|
|
1254
|
+
...options,
|
|
1255
|
+
exclude: excludeList,
|
|
1256
|
+
},
|
|
1257
|
+
);
|
|
1258
|
+
let gemHome =
|
|
1259
|
+
readEnvironmentVariable("CDXGEN_GEM_HOME") ||
|
|
1260
|
+
readEnvironmentVariable("GEM_HOME");
|
|
1261
|
+
if (
|
|
1262
|
+
!gemHome &&
|
|
1263
|
+
(readEnvironmentVariable("BUNDLE_PATH") ||
|
|
1264
|
+
readEnvironmentVariable("GEM_PATH"))
|
|
1265
|
+
) {
|
|
1266
|
+
gemHome =
|
|
1267
|
+
readEnvironmentVariable("BUNDLE_PATH") ||
|
|
1268
|
+
readEnvironmentVariable("GEM_PATH");
|
|
1269
|
+
}
|
|
1270
|
+
// Bundler records the install path and the excluded groups in .bundle/config,
|
|
1271
|
+
// so honour it to locate the gems and to warn about an incomplete BOM.
|
|
1272
|
+
const bundleConfig = parseBundleConfig(join(path, ".bundle", "config"));
|
|
1273
|
+
if (!gemHome && bundleConfig.BUNDLE_PATH) {
|
|
1274
|
+
gemHome = isAbsolute(bundleConfig.BUNDLE_PATH)
|
|
1275
|
+
? bundleConfig.BUNDLE_PATH
|
|
1276
|
+
: join(path, bundleConfig.BUNDLE_PATH);
|
|
1277
|
+
if (DEBUG_MODE) {
|
|
1278
|
+
console.log(`Using the BUNDLE_PATH from .bundle/config: ${gemHome}`);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
const bundleWithout =
|
|
1282
|
+
bundleConfig.BUNDLE_WITHOUT || readEnvironmentVariable("BUNDLE_WITHOUT");
|
|
1283
|
+
if (bundleWithout?.length) {
|
|
1284
|
+
console.log(
|
|
1285
|
+
`NOTE: The bundle groups '${bundleWithout.replaceAll(":", ", ")}' were excluded by bundler, so these gems might be missing from the BOM.`,
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
let isGemHomeEmpty = true;
|
|
1289
|
+
// In deep mode, let's collect all gems that got installed in our custom GEM_HOME directory.
|
|
1290
|
+
// This would improve the accuracy of any security analysis downstream at cost of a slight increase in time.
|
|
1291
|
+
if (options.deep && readEnvironmentVariable("CDXGEN_GEM_HOME")) {
|
|
1292
|
+
const gemHomeSpecFiles = getAllFiles(
|
|
1293
|
+
readEnvironmentVariable("CDXGEN_GEM_HOME") ||
|
|
1294
|
+
readEnvironmentVariable("BUNDLE_PATH"),
|
|
1295
|
+
"**/specifications/**/*.gemspec",
|
|
1296
|
+
options,
|
|
1297
|
+
);
|
|
1298
|
+
if (gemHomeSpecFiles?.length) {
|
|
1299
|
+
isGemHomeEmpty = false;
|
|
1300
|
+
gemspecFiles = gemspecFiles.concat(gemHomeSpecFiles);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
let pkgList = [];
|
|
1304
|
+
let dependencies = [];
|
|
1305
|
+
let rootList = [];
|
|
1306
|
+
const parentComponent = createDefaultParentComponent(path, "gem", options);
|
|
1307
|
+
const gemFileMode = gemFiles.length;
|
|
1308
|
+
const gemLockMode = gemLockFiles.length;
|
|
1309
|
+
if (gemFileMode && !gemLockMode && options.installDeps) {
|
|
1310
|
+
for (const f of gemFiles) {
|
|
1311
|
+
const basePath = dirname(f);
|
|
1312
|
+
console.log("Executing 'bundle install' in", basePath);
|
|
1313
|
+
const result = safeSpawnSync("bundle", ["install"], {
|
|
1314
|
+
cwd: basePath,
|
|
1315
|
+
shell: isWin,
|
|
1316
|
+
});
|
|
1317
|
+
if (result.status !== 0 || result.error) {
|
|
1318
|
+
console.error(
|
|
1319
|
+
"Bundle install has failed. Check if bundle is installed and available in PATH.",
|
|
1320
|
+
);
|
|
1321
|
+
console.log(result.error, result.stderr);
|
|
1322
|
+
options.failOnError && process.exit(1);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
gemLockFiles = getAllFiles(
|
|
1327
|
+
path,
|
|
1328
|
+
`${options.multiProject ? "**/" : ""}Gemfile*.lock`,
|
|
1329
|
+
{
|
|
1330
|
+
...options,
|
|
1331
|
+
exclude: gemLockExcludeList,
|
|
1332
|
+
},
|
|
1333
|
+
);
|
|
1334
|
+
if (gemLockFiles.length) {
|
|
1335
|
+
for (const f of gemLockFiles) {
|
|
1336
|
+
if (DEBUG_MODE) {
|
|
1337
|
+
console.log(`Parsing ${f}`);
|
|
1338
|
+
}
|
|
1339
|
+
const gemLockData = readFileSync(f, { encoding: "utf-8" });
|
|
1340
|
+
const retMap = await parseGemfileLockData(gemLockData, f);
|
|
1341
|
+
if (retMap.pkgList?.length) {
|
|
1342
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
1343
|
+
pkgList = trimComponents(pkgList);
|
|
1344
|
+
}
|
|
1345
|
+
if (retMap.dependenciesList?.length) {
|
|
1346
|
+
dependencies = mergeDependencies(
|
|
1347
|
+
dependencies,
|
|
1348
|
+
retMap.dependenciesList,
|
|
1349
|
+
parentComponent,
|
|
1350
|
+
);
|
|
1351
|
+
}
|
|
1352
|
+
if (retMap.rootList?.length) {
|
|
1353
|
+
rootList = rootList.concat(retMap.rootList);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
// Parsing .gemspec files would help us get more metadata such as description, authors, licenses etc
|
|
1358
|
+
let rootGemspecComponent;
|
|
1359
|
+
if (gemspecFiles.length) {
|
|
1360
|
+
if (!gemLockFiles.length && !hasAnyProjectType(["oci"], options, false)) {
|
|
1361
|
+
console.log(
|
|
1362
|
+
"SBOM generation using only gemspec files is imprecise and results in an inaccurate dependency tree.",
|
|
1363
|
+
);
|
|
1364
|
+
options.failOnError && process.exit(1);
|
|
1365
|
+
}
|
|
1366
|
+
for (const f of gemspecFiles) {
|
|
1367
|
+
const gemspecData = readFileSync(f, { encoding: "utf-8" });
|
|
1368
|
+
const gpkgList = await parseGemspecData(gemspecData, f);
|
|
1369
|
+
if (gpkgList.length) {
|
|
1370
|
+
pkgList = pkgList.concat(gpkgList);
|
|
1371
|
+
pkgList = trimComponents(pkgList);
|
|
1372
|
+
if (
|
|
1373
|
+
!rootGemspecComponent &&
|
|
1374
|
+
dirname(resolve(f)) === resolve(path) &&
|
|
1375
|
+
gpkgList[0]?.name
|
|
1376
|
+
) {
|
|
1377
|
+
rootGemspecComponent = gpkgList[0];
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
if (
|
|
1382
|
+
rootGemspecComponent &&
|
|
1383
|
+
!("project-name" in options) &&
|
|
1384
|
+
options.projectName === undefined
|
|
1385
|
+
) {
|
|
1386
|
+
parentComponent.name = rootGemspecComponent.name;
|
|
1387
|
+
parentComponent.version = rootGemspecComponent.version || "latest";
|
|
1388
|
+
const parentPurl = build({
|
|
1389
|
+
type: "gem",
|
|
1390
|
+
namespace: parentComponent.group || null,
|
|
1391
|
+
name: parentComponent.name,
|
|
1392
|
+
version: parentComponent.version || null,
|
|
1393
|
+
});
|
|
1394
|
+
parentComponent["bom-ref"] = decodeURIComponent(parentPurl);
|
|
1395
|
+
parentComponent["purl"] = parentPurl;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
if (rootList.length) {
|
|
1399
|
+
dependencies = mergeDependencies(
|
|
1400
|
+
dependencies,
|
|
1401
|
+
[
|
|
1402
|
+
{
|
|
1403
|
+
ref: parentComponent["bom-ref"],
|
|
1404
|
+
dependsOn: [...new Set(rootList)].sort(),
|
|
1405
|
+
},
|
|
1406
|
+
],
|
|
1407
|
+
parentComponent,
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
// Should we collect the module names for the gems
|
|
1411
|
+
if (
|
|
1412
|
+
options.resolveClass ||
|
|
1413
|
+
(options.deep && !hasAnyProjectType(["oci"], options, false))
|
|
1414
|
+
) {
|
|
1415
|
+
if (gemHome && !isGemHomeEmpty) {
|
|
1416
|
+
const rubyCommand =
|
|
1417
|
+
readEnvironmentVariable("CDXGEN_RUBY_CMD") ||
|
|
1418
|
+
readEnvironmentVariable("RUBY_CMD") ||
|
|
1419
|
+
"ruby";
|
|
1420
|
+
const bundleCommand =
|
|
1421
|
+
readEnvironmentVariable("CDXGEN_BUNDLE_CMD") || "bundle";
|
|
1422
|
+
let emptyCount = 0;
|
|
1423
|
+
let atleastOneHit = false;
|
|
1424
|
+
console.log(
|
|
1425
|
+
`About the collect the module names for ${pkgList.length} gems. This would take a while ...`,
|
|
1426
|
+
);
|
|
1427
|
+
const gemFilePath = gemFiles?.length > 0 ? dirname(gemFiles[0]) : path;
|
|
1428
|
+
for (const apkg of pkgList) {
|
|
1429
|
+
if (!apkg.name || !apkg.version || apkg.name.startsWith("/")) {
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
const moduleNames = collectGemModuleNames(
|
|
1433
|
+
rubyCommand,
|
|
1434
|
+
bundleCommand,
|
|
1435
|
+
gemHome,
|
|
1436
|
+
apkg.name,
|
|
1437
|
+
gemFilePath,
|
|
1438
|
+
);
|
|
1439
|
+
if (moduleNames.length) {
|
|
1440
|
+
emptyCount = 0;
|
|
1441
|
+
atleastOneHit = true;
|
|
1442
|
+
if (!apkg.properties) {
|
|
1443
|
+
apkg.properties = [];
|
|
1444
|
+
}
|
|
1445
|
+
apkg.properties.push({
|
|
1446
|
+
name: "internal:Namespaces",
|
|
1447
|
+
value: moduleNames.join(", "),
|
|
1448
|
+
});
|
|
1449
|
+
} else {
|
|
1450
|
+
emptyCount++;
|
|
1451
|
+
}
|
|
1452
|
+
// Circuit breaker
|
|
1453
|
+
if (!atleastOneHit && emptyCount >= 5) {
|
|
1454
|
+
console.log(
|
|
1455
|
+
"Unable to collect the module names for all the gems. Resolve the errors reported and re-run cdxgen.",
|
|
1456
|
+
);
|
|
1457
|
+
if (DEBUG_MODE) {
|
|
1458
|
+
console.log(
|
|
1459
|
+
"Tried everything to get the `--deep` mode working? Please create an issue with a sample repo to reproduce this problem. https://github.com/cdxgen/cdxgen/issues",
|
|
1460
|
+
);
|
|
1461
|
+
}
|
|
1462
|
+
break;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
if (DEBUG_MODE && atleastOneHit) {
|
|
1466
|
+
console.log(
|
|
1467
|
+
"Successfully obtained the module names for some component gems. You can find them under a property named `internal:Namespaces`.",
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1470
|
+
// Clean up
|
|
1471
|
+
if (readEnvironmentVariable("CDXGEN_GEM_HOME")?.startsWith(getTmpDir())) {
|
|
1472
|
+
safeRmSync(readEnvironmentVariable("CDXGEN_GEM_HOME"), {
|
|
1473
|
+
recursive: true,
|
|
1474
|
+
force: true,
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
} else {
|
|
1478
|
+
if (readEnvironmentVariable("CDXGEN_GEM_HOME")) {
|
|
1479
|
+
console.log(
|
|
1480
|
+
`${readEnvironmentVariable("CDXGEN_GEM_HOME")} was empty. Ensure "bundle install" command was successful prior to invoking cdxgen.`,
|
|
1481
|
+
);
|
|
1482
|
+
} else {
|
|
1483
|
+
console.log(
|
|
1484
|
+
"Set the environment variable CDXGEN_GEM_HOME or GEM_HOME to collect the module names for installed gems.",
|
|
1485
|
+
);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
// Enrich from the caches on this machine. This is free compared to a registry
|
|
1490
|
+
// lookup, gives us the sha256 of the exact native build, and unlike the
|
|
1491
|
+
// registry lookups it also works in dry-run mode.
|
|
1492
|
+
pkgList = await enrichGemsFromLocalCache(pkgList, { gemHome });
|
|
1493
|
+
return buildBomNSData(options, pkgList, "gem", {
|
|
1494
|
+
src: path,
|
|
1495
|
+
dependencies,
|
|
1496
|
+
parentComponent,
|
|
1497
|
+
filename: gemLockFiles.join(", "),
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
/**
|
|
1502
|
+
* Function to create bom string for csharp projects
|
|
1503
|
+
*
|
|
1504
|
+
* @param {string} path to the project
|
|
1505
|
+
* @param {Object} options Parse options from the cli
|
|
1506
|
+
* @returns {Promise<Object|undefined>} Promise resolving to BOM object
|
|
1507
|
+
*/
|
|
1508
|
+
export async function createCsharpBom(path, options) {
|
|
1509
|
+
let manifestFiles = [];
|
|
1510
|
+
let pkgData;
|
|
1511
|
+
let dependencies = [];
|
|
1512
|
+
if (options?.lifecycle?.includes("post-build")) {
|
|
1513
|
+
return createBinaryBom(path, options);
|
|
1514
|
+
}
|
|
1515
|
+
let parentComponent = createDefaultParentComponent(path, "nuget", options);
|
|
1516
|
+
const slnFiles = getAllFiles(
|
|
1517
|
+
path,
|
|
1518
|
+
`${options.multiProject ? "**/" : ""}*.sln*`,
|
|
1519
|
+
options,
|
|
1520
|
+
);
|
|
1521
|
+
const csProjFiles = getAllFiles(
|
|
1522
|
+
path,
|
|
1523
|
+
`${options.multiProject ? "**/" : ""}*.{cs,vb,fs,ts,hmi,plc}proj`,
|
|
1524
|
+
options,
|
|
1525
|
+
);
|
|
1526
|
+
const propsFiles = getAllFiles(
|
|
1527
|
+
path,
|
|
1528
|
+
`${options.multiProject ? "**/" : ""}*.props`,
|
|
1529
|
+
options,
|
|
1530
|
+
);
|
|
1531
|
+
const pkgConfigFiles = getAllFiles(
|
|
1532
|
+
path,
|
|
1533
|
+
`${options.multiProject ? "**/" : ""}packages.config`,
|
|
1534
|
+
options,
|
|
1535
|
+
);
|
|
1536
|
+
let projAssetsFiles = getAllFiles(
|
|
1537
|
+
path,
|
|
1538
|
+
`${options.multiProject ? "**/" : ""}project.assets.json`,
|
|
1539
|
+
options,
|
|
1540
|
+
);
|
|
1541
|
+
let pkgLockFiles = getAllFiles(
|
|
1542
|
+
path,
|
|
1543
|
+
`${options.multiProject ? "**/" : ""}packages.lock.json`,
|
|
1544
|
+
options,
|
|
1545
|
+
);
|
|
1546
|
+
const paketLockFiles = getAllFiles(
|
|
1547
|
+
path,
|
|
1548
|
+
`${options.multiProject ? "**/" : ""}paket.lock`,
|
|
1549
|
+
options,
|
|
1550
|
+
);
|
|
1551
|
+
let nupkgFiles = getAllFiles(
|
|
1552
|
+
path,
|
|
1553
|
+
`${options.multiProject ? "**/" : ""}*.nupkg`,
|
|
1554
|
+
options,
|
|
1555
|
+
);
|
|
1556
|
+
// Support for detecting and suggesting build tools for this project
|
|
1557
|
+
// We parse all the .csproj files to collect the target framework strings
|
|
1558
|
+
if (isFeatureEnabled(options, "suggest-build-tools")) {
|
|
1559
|
+
const targetFrameworks = new Set();
|
|
1560
|
+
for (const f of csProjFiles) {
|
|
1561
|
+
const csProjData = readFileSync(f, { encoding: "utf-8" });
|
|
1562
|
+
const retMap = parseCsProjData(csProjData, f, {});
|
|
1563
|
+
if (retMap?.parentComponent?.properties) {
|
|
1564
|
+
retMap.parentComponent.properties
|
|
1565
|
+
.filter(
|
|
1566
|
+
(p) =>
|
|
1567
|
+
p.name === "cdx:dotnet:target_framework" && p.value.trim().length,
|
|
1568
|
+
)
|
|
1569
|
+
.forEach((p) => {
|
|
1570
|
+
p.value
|
|
1571
|
+
.split(";")
|
|
1572
|
+
.filter((v) => v.trim().length && !v.startsWith("$("))
|
|
1573
|
+
.forEach((v) => {
|
|
1574
|
+
targetFrameworks.add(v);
|
|
1575
|
+
});
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
console.log("Target frameworks found:", Array.from(targetFrameworks));
|
|
1580
|
+
}
|
|
1581
|
+
// Support for automatic restore for .Net projects
|
|
1582
|
+
if (
|
|
1583
|
+
options.installDeps &&
|
|
1584
|
+
!projAssetsFiles.length &&
|
|
1585
|
+
!pkgLockFiles.length &&
|
|
1586
|
+
!paketLockFiles.length
|
|
1587
|
+
) {
|
|
1588
|
+
const filesToRestore = slnFiles.concat(csProjFiles);
|
|
1589
|
+
for (const f of filesToRestore) {
|
|
1590
|
+
let buildCmd = options.projectType?.includes("dotnet-framework")
|
|
1591
|
+
? "nuget"
|
|
1592
|
+
: "dotnet";
|
|
1593
|
+
let buildArgs = options.projectType?.includes("dotnet-framework")
|
|
1594
|
+
? [
|
|
1595
|
+
"restore",
|
|
1596
|
+
"-NonInteractive",
|
|
1597
|
+
"-PackageSaveMode",
|
|
1598
|
+
"nuspec;nupkg",
|
|
1599
|
+
"-Verbosity",
|
|
1600
|
+
"quiet",
|
|
1601
|
+
]
|
|
1602
|
+
: ["restore", "--force", "--ignore-failed-sources", f];
|
|
1603
|
+
if (isWin && options.projectType?.includes("dotnet-framework")) {
|
|
1604
|
+
buildCmd = "msbuild";
|
|
1605
|
+
buildArgs = ["-t:restore", "-p:RestorePackagesConfig=true"];
|
|
1606
|
+
}
|
|
1607
|
+
if (DEBUG_MODE) {
|
|
1608
|
+
const basePath = dirname(f);
|
|
1609
|
+
console.log(
|
|
1610
|
+
`Executing '${buildCmd} ${buildArgs.join(" ")}' in ${basePath}`,
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1613
|
+
const result = safeSpawnSync(buildCmd, buildArgs, {
|
|
1614
|
+
cwd: path,
|
|
1615
|
+
shell: isWin,
|
|
1616
|
+
env: { ...process.env, DOTNET_ROLL_FORWARD: "Major" },
|
|
1617
|
+
});
|
|
1618
|
+
if (DEBUG_MODE && (result.status !== 0 || result.error)) {
|
|
1619
|
+
if (
|
|
1620
|
+
result?.stderr?.includes(
|
|
1621
|
+
"only packages.config files will be restored",
|
|
1622
|
+
) &&
|
|
1623
|
+
buildCmd === "nuget"
|
|
1624
|
+
) {
|
|
1625
|
+
console.log(
|
|
1626
|
+
`This project needs to be restored using msbuild. Example: 'msbuild -t:restore -p:RestorePackagesConfig=true'. cdxgen is attempting to use ${buildCmd}, which might result in an incomplete SBOM!`,
|
|
1627
|
+
);
|
|
1628
|
+
if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") !== "true") {
|
|
1629
|
+
console.log(
|
|
1630
|
+
"Ensure the restore step is performed prior to invoking cdxgen.",
|
|
1631
|
+
);
|
|
1632
|
+
} else {
|
|
1633
|
+
console.log(
|
|
1634
|
+
"TIP: msbuild is not available for Linux. Try using a Windows build agent to generate an SBOM for this project.",
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
options.failOnError && process.exit(1);
|
|
1638
|
+
}
|
|
1639
|
+
if (result?.stderr?.includes("To install missing framework")) {
|
|
1640
|
+
console.log(
|
|
1641
|
+
"This project requires a specific version of dotnet sdk to be installed. The cdxgen container image bundles dotnet SDK 8.0, which might be incompatible.",
|
|
1642
|
+
);
|
|
1643
|
+
console.log(
|
|
1644
|
+
"TIP: Try using the custom `ghcr.io/cdxgen/cdxgen-debian-dotnet8:v13` or `ghcr.io/cdxgen/cdxgen-debian-dotnet9:v13` container images.",
|
|
1645
|
+
);
|
|
1646
|
+
} else if (
|
|
1647
|
+
result?.stderr?.includes("is not found on source") ||
|
|
1648
|
+
result?.stderr?.includes("Unable to find version")
|
|
1649
|
+
) {
|
|
1650
|
+
console.log(
|
|
1651
|
+
`The project ${f} refers to private packages that are not available on nuget.org!`,
|
|
1652
|
+
);
|
|
1653
|
+
console.log(
|
|
1654
|
+
"TIP: Authenticate with any private registries such as Azure Artifacts feed before running cdxgen. Alternatively, commit the contents of the 'packages' folder to the repository.",
|
|
1655
|
+
);
|
|
1656
|
+
} else if (result?.stderr?.includes("but the current NuGet version")) {
|
|
1657
|
+
if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") !== "true") {
|
|
1658
|
+
console.log(
|
|
1659
|
+
"TIP: Try downloading the correct version from here: https://learn.microsoft.com/en-us/nuget/install-nuget-client-tools",
|
|
1660
|
+
);
|
|
1661
|
+
} else {
|
|
1662
|
+
console.log(
|
|
1663
|
+
"TIP: This project requires a specific version of nuget client to be installed. Try using a Windows build agent to generate an SBOM for this project.",
|
|
1664
|
+
);
|
|
1665
|
+
}
|
|
1666
|
+
} else {
|
|
1667
|
+
console.error(
|
|
1668
|
+
`Restore has failed. Check if ${buildCmd} is installed and available in PATH.`,
|
|
1669
|
+
);
|
|
1670
|
+
console.log(
|
|
1671
|
+
"Authenticate with any private registries such as Azure Artifacts feed before running cdxgen.",
|
|
1672
|
+
);
|
|
1673
|
+
if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") !== "true") {
|
|
1674
|
+
console.log(
|
|
1675
|
+
"Alternatively, try using the custom `ghcr.io/cdxgen/cdxgen-debian-dotnet8:v13` container image, which bundles nuget (mono) and a range of dotnet SDKs.",
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
console.log("---------");
|
|
1680
|
+
if (result.stderr) {
|
|
1681
|
+
console.log(result.stderr);
|
|
1682
|
+
} else if (result.stdout) {
|
|
1683
|
+
console.log(result.stdout);
|
|
1684
|
+
}
|
|
1685
|
+
console.log("---------");
|
|
1686
|
+
options.failOnError && process.exit(1);
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
// Collect the assets, lock, and nupkg files generated from restore
|
|
1690
|
+
projAssetsFiles = getAllFiles(
|
|
1691
|
+
path,
|
|
1692
|
+
`${options.multiProject ? "**/" : ""}project.assets.json`,
|
|
1693
|
+
options,
|
|
1694
|
+
);
|
|
1695
|
+
pkgLockFiles = getAllFiles(
|
|
1696
|
+
path,
|
|
1697
|
+
`${options.multiProject ? "**/" : ""}packages.lock.json`,
|
|
1698
|
+
options,
|
|
1699
|
+
);
|
|
1700
|
+
nupkgFiles = getAllFiles(
|
|
1701
|
+
path,
|
|
1702
|
+
`${options.multiProject ? "**/" : ""}*.nupkg`,
|
|
1703
|
+
options,
|
|
1704
|
+
);
|
|
1705
|
+
}
|
|
1706
|
+
let pkgList = [];
|
|
1707
|
+
const parentDependsOn = new Set();
|
|
1708
|
+
if (nupkgFiles.length && projAssetsFiles.length === 0) {
|
|
1709
|
+
manifestFiles = manifestFiles.concat(nupkgFiles);
|
|
1710
|
+
// When parsing nupkg files, only version ranges will be specified under dependencies
|
|
1711
|
+
// To resolve the version, we need to track the mapping between name and resolved versions here
|
|
1712
|
+
let dependenciesMap = {};
|
|
1713
|
+
const pkgNameVersions = {};
|
|
1714
|
+
for (const nf of nupkgFiles) {
|
|
1715
|
+
if (DEBUG_MODE) {
|
|
1716
|
+
console.log(`Parsing ${nf}`);
|
|
1717
|
+
}
|
|
1718
|
+
const retMap = await parseNupkg(nf);
|
|
1719
|
+
if (retMap?.pkgList?.length) {
|
|
1720
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
1721
|
+
for (const d of retMap.pkgList) {
|
|
1722
|
+
parentDependsOn.add(d["bom-ref"]);
|
|
1723
|
+
pkgNameVersions[d.name] = d.version;
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
if (retMap?.dependenciesMap) {
|
|
1727
|
+
dependenciesMap = { ...dependenciesMap, ...retMap.dependenciesMap };
|
|
1728
|
+
}
|
|
1729
|
+
} // end for
|
|
1730
|
+
for (const k of Object.keys(dependenciesMap)) {
|
|
1731
|
+
const dependsOn = dependenciesMap[k].map((p) => {
|
|
1732
|
+
const ver = pkgNameVersions[p] || "latest";
|
|
1733
|
+
const purl = nugetPurl(p, ver);
|
|
1734
|
+
return purl ? decodeURIComponent(purl) : `library:${p}:${ver}`;
|
|
1735
|
+
});
|
|
1736
|
+
dependencies.push({ ref: k, dependsOn: [...new Set(dependsOn)].sort() });
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
// In a multi-project scan, different projects may use different manifest
|
|
1740
|
+
// formats: modern SDK-style (project.assets.json / packages.lock.json) or
|
|
1741
|
+
// legacy (packages.config). Apply the assets > lock > config precedence per
|
|
1742
|
+
// project directory instead of across the whole scan, so dependencies from
|
|
1743
|
+
// one project's manifest are not dropped just because another format exists
|
|
1744
|
+
// elsewhere in the scan.
|
|
1745
|
+
const assetsProjectDirs = new Set(
|
|
1746
|
+
projAssetsFiles.map((af) => {
|
|
1747
|
+
// project.assets.json is generated under <project>/obj/
|
|
1748
|
+
const d = dirname(af);
|
|
1749
|
+
return basename(d) === "obj" ? dirname(d) : d;
|
|
1750
|
+
}),
|
|
1751
|
+
);
|
|
1752
|
+
const lockProjectDirs = new Set(pkgLockFiles.map((af) => dirname(af)));
|
|
1753
|
+
// project.assets.json parsing
|
|
1754
|
+
if (projAssetsFiles.length) {
|
|
1755
|
+
manifestFiles = manifestFiles.concat(projAssetsFiles);
|
|
1756
|
+
for (const af of projAssetsFiles) {
|
|
1757
|
+
if (DEBUG_MODE) {
|
|
1758
|
+
console.log(`Parsing ${af}`);
|
|
1759
|
+
}
|
|
1760
|
+
pkgData = readFileSync(af, { encoding: "utf-8" });
|
|
1761
|
+
const results = parseCsProjAssetsData(pkgData, af);
|
|
1762
|
+
const deps = results["dependenciesList"];
|
|
1763
|
+
const dlist = results["pkgList"];
|
|
1764
|
+
if (dlist?.length) {
|
|
1765
|
+
pkgList = pkgList.concat(dlist);
|
|
1766
|
+
}
|
|
1767
|
+
if (deps?.length) {
|
|
1768
|
+
dependencies = mergeDependencies(dependencies, deps, parentComponent);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
// We are now in a scenario where the restore operation didn't yield correct project.assets.json files.
|
|
1772
|
+
// This usually happens when restore was performed with an incorrect version of the SDK.
|
|
1773
|
+
if (!pkgList.length || dependencies.length < 2) {
|
|
1774
|
+
console.log(
|
|
1775
|
+
"Unable to obtain the correct dependency tree from the project.assets.json files. Ensure the correct version of the dotnet SDK was installed and used.",
|
|
1776
|
+
);
|
|
1777
|
+
console.log(
|
|
1778
|
+
"1. Create a global.json file in the project directory to specify the required version of the dotnet SDK.",
|
|
1779
|
+
);
|
|
1780
|
+
console.log(
|
|
1781
|
+
"2. Use the environment variable `DOTNET_ROLL_FORWARD` to roll forward to a closest available SDK such as .Net core or dotnet 6.",
|
|
1782
|
+
);
|
|
1783
|
+
console.log(
|
|
1784
|
+
"3. If the project uses the legacy .Net Framework 4.6/4.7/4.8, it might require execution on Windows.",
|
|
1785
|
+
);
|
|
1786
|
+
console.log(
|
|
1787
|
+
"Alternatively, try using the custom `ghcr.io/cdxgen/cdxgen-dotnet:v13` container image, which bundles a range of dotnet SDKs.",
|
|
1788
|
+
);
|
|
1789
|
+
options.failOnError && process.exit(1);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
// packages.lock.json parsing for any project without a project.assets.json
|
|
1793
|
+
const pkgLockToParse = pkgLockFiles.filter(
|
|
1794
|
+
(af) => !assetsProjectDirs.has(dirname(af)),
|
|
1795
|
+
);
|
|
1796
|
+
if (pkgLockToParse.length) {
|
|
1797
|
+
manifestFiles = manifestFiles.concat(pkgLockToParse);
|
|
1798
|
+
// packages.lock.json from nuget
|
|
1799
|
+
for (const af of pkgLockToParse) {
|
|
1800
|
+
if (DEBUG_MODE) {
|
|
1801
|
+
console.log(`Parsing ${af}`);
|
|
1802
|
+
}
|
|
1803
|
+
pkgData = readFileSync(af, { encoding: "utf-8" });
|
|
1804
|
+
const results = parseCsPkgLockData(pkgData, af);
|
|
1805
|
+
const deps = results["dependenciesList"];
|
|
1806
|
+
const dlist = results["pkgList"];
|
|
1807
|
+
const rootList = results["rootList"];
|
|
1808
|
+
if (dlist?.length) {
|
|
1809
|
+
pkgList = pkgList.concat(dlist);
|
|
1810
|
+
}
|
|
1811
|
+
if (deps?.length) {
|
|
1812
|
+
dependencies = mergeDependencies(dependencies, deps, parentComponent);
|
|
1813
|
+
}
|
|
1814
|
+
// Keep track of the direct dependencies so that we can construct one complete
|
|
1815
|
+
// list after processing all lock files
|
|
1816
|
+
if (rootList?.length) {
|
|
1817
|
+
for (const p of rootList) {
|
|
1818
|
+
parentDependsOn.add(p["bom-ref"]);
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
// packages.config parsing for any project without a modern manifest
|
|
1824
|
+
// (project.assets.json / packages.lock.json) covering the same directory
|
|
1825
|
+
const pkgConfigToParse = pkgConfigFiles.filter((f) => {
|
|
1826
|
+
const projDir = dirname(f);
|
|
1827
|
+
return !assetsProjectDirs.has(projDir) && !lockProjectDirs.has(projDir);
|
|
1828
|
+
});
|
|
1829
|
+
if (pkgConfigToParse.length) {
|
|
1830
|
+
manifestFiles = manifestFiles.concat(pkgConfigToParse);
|
|
1831
|
+
// Versions already resolved from project.assets.json / packages.lock.json
|
|
1832
|
+
// can backfill templated or missing versions in packages.config
|
|
1833
|
+
const resolvedVersions = {};
|
|
1834
|
+
for (const p of pkgList) {
|
|
1835
|
+
if (p.name && p.version) {
|
|
1836
|
+
resolvedVersions[p.name] = p.version;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
// packages.config parsing
|
|
1840
|
+
for (const f of pkgConfigToParse) {
|
|
1841
|
+
if (DEBUG_MODE) {
|
|
1842
|
+
console.log(`Parsing ${f}`);
|
|
1843
|
+
}
|
|
1844
|
+
pkgData = readFileSync(f, { encoding: "utf-8" });
|
|
1845
|
+
const dlist = parseCsPkgData(pkgData, f, resolvedVersions);
|
|
1846
|
+
if (dlist?.length) {
|
|
1847
|
+
pkgList = pkgList.concat(dlist);
|
|
1848
|
+
for (const d of dlist) {
|
|
1849
|
+
parentDependsOn.add(d["bom-ref"]);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
if (paketLockFiles.length) {
|
|
1855
|
+
manifestFiles = manifestFiles.concat(paketLockFiles);
|
|
1856
|
+
// paket.lock parsing
|
|
1857
|
+
for (const f of paketLockFiles) {
|
|
1858
|
+
if (DEBUG_MODE) {
|
|
1859
|
+
console.log(`Parsing ${f}`);
|
|
1860
|
+
}
|
|
1861
|
+
pkgData = readFileSync(f, { encoding: "utf-8" });
|
|
1862
|
+
const results = parsePaketLockData(pkgData, f);
|
|
1863
|
+
const dlist = results.pkgList;
|
|
1864
|
+
const deps = results.dependenciesList;
|
|
1865
|
+
if (dlist?.length) {
|
|
1866
|
+
pkgList = pkgList.concat(dlist);
|
|
1867
|
+
}
|
|
1868
|
+
if (deps?.length) {
|
|
1869
|
+
dependencies = mergeDependencies(dependencies, deps, parentComponent);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
const pkgNameVersions = {};
|
|
1874
|
+
let services = [];
|
|
1875
|
+
if (csProjFiles.length) {
|
|
1876
|
+
manifestFiles = manifestFiles.concat(csProjFiles);
|
|
1877
|
+
// Parsing csproj is quite error-prone. Some project files may not have versions specified
|
|
1878
|
+
// To work around this, we make use of the version from the existing list
|
|
1879
|
+
for (const p of pkgList) {
|
|
1880
|
+
if (p.version) {
|
|
1881
|
+
pkgNameVersions[p.name] = p.version;
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
let msbuildInstalled = false;
|
|
1885
|
+
let pkgVersionLabelCandidates = {};
|
|
1886
|
+
const result = safeSpawnSync(DOTNET_CMD, ["msbuild --version"], {
|
|
1887
|
+
shell: isWin,
|
|
1888
|
+
});
|
|
1889
|
+
if (result.status === 0 && !result.error && result.stdout.trim()) {
|
|
1890
|
+
msbuildInstalled = true;
|
|
1891
|
+
} else {
|
|
1892
|
+
pkgVersionLabelCandidates = getPropertyGroupTextNodes(propsFiles);
|
|
1893
|
+
}
|
|
1894
|
+
// Directory.Packages.props can sit above the directory being scanned, so it is
|
|
1895
|
+
// resolved per project file by walking up rather than from the props glob below.
|
|
1896
|
+
// The cache keeps a repository with many projects from re-parsing the same file.
|
|
1897
|
+
const centralVersionsCache = {};
|
|
1898
|
+
// .csproj parsing
|
|
1899
|
+
for (const f of csProjFiles) {
|
|
1900
|
+
if (DEBUG_MODE) {
|
|
1901
|
+
console.log(`Parsing ${f}`);
|
|
1902
|
+
}
|
|
1903
|
+
const csProjData = readFileSync(f, { encoding: "utf-8" });
|
|
1904
|
+
const retMap = parseCsProjData(
|
|
1905
|
+
csProjData,
|
|
1906
|
+
f,
|
|
1907
|
+
pkgNameVersions,
|
|
1908
|
+
msbuildInstalled,
|
|
1909
|
+
pkgVersionLabelCandidates,
|
|
1910
|
+
getCentralPackageVersions(f, centralVersionsCache),
|
|
1911
|
+
);
|
|
1912
|
+
if (retMap?.parentComponent?.purl) {
|
|
1913
|
+
// If there are multiple project files, track the parent components using nested components
|
|
1914
|
+
if (csProjFiles.length > 1) {
|
|
1915
|
+
if (!parentComponent.components) {
|
|
1916
|
+
parentComponent.components = [];
|
|
1917
|
+
}
|
|
1918
|
+
parentComponent.components.push(retMap.parentComponent);
|
|
1919
|
+
} else {
|
|
1920
|
+
// There is only one project file. Make it the parent.
|
|
1921
|
+
parentComponent = retMap.parentComponent;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
if (retMap?.pkgList?.length) {
|
|
1925
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
1926
|
+
}
|
|
1927
|
+
if (retMap.dependencies?.length) {
|
|
1928
|
+
dependencies = mergeDependencies(
|
|
1929
|
+
dependencies,
|
|
1930
|
+
retMap.dependencies,
|
|
1931
|
+
parentComponent,
|
|
1932
|
+
);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
if (pkgList.length) {
|
|
1937
|
+
pkgList = trimComponents(pkgList);
|
|
1938
|
+
// Perform deep analysis using dosai
|
|
1939
|
+
if (options.deep) {
|
|
1940
|
+
const slicesFile = resolve(
|
|
1941
|
+
options.depsSlicesFile
|
|
1942
|
+
? join(path, options.depsSlicesFile)
|
|
1943
|
+
: join(getTmpDir(), "dosai.json"),
|
|
1944
|
+
);
|
|
1945
|
+
// Create the slices file if it doesn't exist
|
|
1946
|
+
if (!safeExistsSync(slicesFile)) {
|
|
1947
|
+
thoughtLog(
|
|
1948
|
+
"Alright, the next step is to invoke the dosai command to identify evidence of occurrences for various components.",
|
|
1949
|
+
);
|
|
1950
|
+
const sliceResult = createDosaiMethodsSlice(
|
|
1951
|
+
resolve(path),
|
|
1952
|
+
resolve(slicesFile),
|
|
1953
|
+
options,
|
|
1954
|
+
);
|
|
1955
|
+
if (!sliceResult && DEBUG_MODE) {
|
|
1956
|
+
console.log(
|
|
1957
|
+
"Slicing with dosai was unsuccessful. Check the errors reported in the logs above.",
|
|
1958
|
+
);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
pkgList = addEvidenceForDotnet(pkgList, slicesFile);
|
|
1962
|
+
const methodsSlice = readDosaiJsonFile(slicesFile);
|
|
1963
|
+
const servicesMap = collectDosaiServicesFromMethods(methodsSlice, {});
|
|
1964
|
+
services = normalizeDosaiServiceMap(servicesMap);
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
// Parent dependency tree
|
|
1968
|
+
if (parentDependsOn.size && parentComponent?.["bom-ref"]) {
|
|
1969
|
+
dependencies.splice(0, 0, {
|
|
1970
|
+
ref: parentComponent["bom-ref"],
|
|
1971
|
+
dependsOn: Array.from(parentDependsOn).sort(),
|
|
1972
|
+
});
|
|
1973
|
+
}
|
|
1974
|
+
if (shouldFetchLicense()) {
|
|
1975
|
+
const retMap = await getNugetMetadata(pkgList, dependencies);
|
|
1976
|
+
if (retMap.dependencies?.length) {
|
|
1977
|
+
dependencies = mergeDependencies(
|
|
1978
|
+
dependencies,
|
|
1979
|
+
retMap.dependencies,
|
|
1980
|
+
parentComponent,
|
|
1981
|
+
);
|
|
1982
|
+
}
|
|
1983
|
+
pkgList = trimComponents(pkgList);
|
|
1984
|
+
}
|
|
1985
|
+
return buildBomNSData(options, pkgList, "nuget", {
|
|
1986
|
+
src: path,
|
|
1987
|
+
filename: manifestFiles.join(", "),
|
|
1988
|
+
dependencies,
|
|
1989
|
+
parentComponent,
|
|
1990
|
+
services,
|
|
1991
|
+
tools: options.deep ? getPluginToolComponents(["dosai"]) : [],
|
|
1992
|
+
});
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
/**
|
|
1996
|
+
* Function to create bom object for cryptographic certificate files
|
|
1997
|
+
*
|
|
1998
|
+
* @param {string} path to the project
|
|
1999
|
+
* @param {Object} options Parse options from the cli
|
|
2000
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
2001
|
+
*/
|
|
2002
|
+
export async function createCryptoCertsBom(path, options) {
|
|
2003
|
+
if (!isCycloneDxComponentTypeEnabled("cryptographic-asset", options)) {
|
|
2004
|
+
return {
|
|
2005
|
+
bomJson: {
|
|
2006
|
+
components: [],
|
|
2007
|
+
},
|
|
2008
|
+
};
|
|
2009
|
+
}
|
|
2010
|
+
const pkgList = [];
|
|
2011
|
+
const certFiles = getAllFiles(
|
|
2012
|
+
path,
|
|
2013
|
+
`${
|
|
2014
|
+
options.multiProject ? "**/" : ""
|
|
2015
|
+
}*.{p12,jks,jceks,bks,keystore,key,pem,cer,gpg,pub}`,
|
|
2016
|
+
options,
|
|
2017
|
+
);
|
|
2018
|
+
const certHashes = await mapWithConcurrency(certFiles, (f) =>
|
|
2019
|
+
checksumFile("sha256", f),
|
|
2020
|
+
);
|
|
2021
|
+
for (let ci = 0; ci < certFiles.length; ci++) {
|
|
2022
|
+
const f = certFiles[ci];
|
|
2023
|
+
const fileHash = certHashes[ci];
|
|
2024
|
+
const name = basename(f);
|
|
2025
|
+
let evidence;
|
|
2026
|
+
if (options.evidence) {
|
|
2027
|
+
const identityEvidence = {
|
|
2028
|
+
field: "name",
|
|
2029
|
+
confidence: 1,
|
|
2030
|
+
concludedValue: name,
|
|
2031
|
+
methods: [
|
|
2032
|
+
{
|
|
2033
|
+
technique: "filename",
|
|
2034
|
+
confidence: 1,
|
|
2035
|
+
value: f,
|
|
2036
|
+
},
|
|
2037
|
+
],
|
|
2038
|
+
};
|
|
2039
|
+
evidence = {
|
|
2040
|
+
identity:
|
|
2041
|
+
options.specVersion >= 1.6 ? [identityEvidence] : identityEvidence,
|
|
2042
|
+
occurrences: [{ location: f }],
|
|
2043
|
+
};
|
|
2044
|
+
}
|
|
2045
|
+
const apkg = {
|
|
2046
|
+
name,
|
|
2047
|
+
type: "cryptographic-asset",
|
|
2048
|
+
version: fileHash,
|
|
2049
|
+
"bom-ref": `crypto/certificate/${name}@sha256:${fileHash}`,
|
|
2050
|
+
cryptoProperties: {
|
|
2051
|
+
assetType: "certificate",
|
|
2052
|
+
algorithmProperties: {
|
|
2053
|
+
executionEnvironment: "unknown",
|
|
2054
|
+
implementationPlatform: "unknown",
|
|
2055
|
+
},
|
|
2056
|
+
},
|
|
2057
|
+
...(evidence ? { evidence } : {}),
|
|
2058
|
+
properties: [{ name: "internal:SrcFile", value: f }],
|
|
2059
|
+
};
|
|
2060
|
+
pkgList.push(apkg);
|
|
2061
|
+
}
|
|
2062
|
+
const sourceCryptoComponents = await collectSourceCryptoComponents(
|
|
2063
|
+
path,
|
|
2064
|
+
options,
|
|
2065
|
+
);
|
|
2066
|
+
if (sourceCryptoComponents.length) {
|
|
2067
|
+
pkgList.push(...sourceCryptoComponents);
|
|
2068
|
+
}
|
|
2069
|
+
if (shouldCollectDosaiCrypto(path, options)) {
|
|
2070
|
+
const dosaiCryptoComponents = await collectDosaiCryptoComponents(
|
|
2071
|
+
path,
|
|
2072
|
+
options,
|
|
2073
|
+
);
|
|
2074
|
+
if (dosaiCryptoComponents.length) {
|
|
2075
|
+
pkgList.push(...dosaiCryptoComponents);
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
return {
|
|
2079
|
+
bomJson: {
|
|
2080
|
+
components: filterInvalidCryptoComponents(pkgList),
|
|
2081
|
+
},
|
|
2082
|
+
};
|
|
2083
|
+
}
|