@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
package/lib/cli/index.js
ADDED
|
@@ -0,0 +1,2759 @@
|
|
|
1
|
+
import {
|
|
2
|
+
accessSync,
|
|
3
|
+
constants,
|
|
4
|
+
lstatSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
statSync,
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import { platform as _platform, availableParallelism, homedir } from "node:os";
|
|
9
|
+
import { basename, join } from "node:path";
|
|
10
|
+
import process from "node:process";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
cdxgenAgent,
|
|
14
|
+
DEBUG_MODE,
|
|
15
|
+
isAllowedHttpHost,
|
|
16
|
+
isDryRun,
|
|
17
|
+
readEnvironmentVariable,
|
|
18
|
+
recordActivity,
|
|
19
|
+
setActivityContext,
|
|
20
|
+
} from "../core/activity.js";
|
|
21
|
+
import { hasAnyProjectType, PROJECT_TYPE_ALIASES } from "../core/env.js";
|
|
22
|
+
import {
|
|
23
|
+
clearFileDiscoveryCache,
|
|
24
|
+
getAllFiles,
|
|
25
|
+
getTmpDir,
|
|
26
|
+
safeExistsSync,
|
|
27
|
+
safeRmSync,
|
|
28
|
+
setDirWalkCacheRoot,
|
|
29
|
+
} from "../core/fs.js";
|
|
30
|
+
import { thoughtLog } from "../core/logger.js";
|
|
31
|
+
import { mapWithConcurrency } from "../core/parallel.js";
|
|
32
|
+
import { dirNameStr } from "../core/paths.js";
|
|
33
|
+
import { ui } from "../core/ui.js";
|
|
34
|
+
import {
|
|
35
|
+
parseBitbucketPipelinesFile,
|
|
36
|
+
parseContainerFile,
|
|
37
|
+
parseContainerSpecData,
|
|
38
|
+
parseOpenapiSpecData,
|
|
39
|
+
parsePrivadoFile,
|
|
40
|
+
} from "../ecosystems/parsers-misc.js";
|
|
41
|
+
import { isPyLockFile } from "../ecosystems/pylockutils.js";
|
|
42
|
+
import {
|
|
43
|
+
buildDependencyTrackBomPayload,
|
|
44
|
+
getDependencyTrackBomApiUrl,
|
|
45
|
+
} from "../helpers/remote/dependency-track.js";
|
|
46
|
+
import { optionIncludesAiInventoryProjectType } from "../inventory/aiInventory.js";
|
|
47
|
+
import { isCycloneDxComponentTypeEnabled } from "../inventory/bomUtils.js";
|
|
48
|
+
import {
|
|
49
|
+
mergeDependencies,
|
|
50
|
+
mergeServices,
|
|
51
|
+
trimComponents,
|
|
52
|
+
} from "../inventory/depsUtils.js";
|
|
53
|
+
import { buildDynamicComponents } from "../inventory/dynamic.js";
|
|
54
|
+
import { convertOSQueryResults } from "../inventory/evidenceUtils.js";
|
|
55
|
+
import {
|
|
56
|
+
createHbomDocument,
|
|
57
|
+
ensureHbomRuntimeSupport,
|
|
58
|
+
ensureNoMixedHbomProjectTypes,
|
|
59
|
+
hasHbomProjectType,
|
|
60
|
+
} from "../inventory/hbom.js";
|
|
61
|
+
import { mergeHostInventoryBoms } from "../inventory/hostTopology.js";
|
|
62
|
+
// Imported directly rather than through the utils.js barrel: purl validity is
|
|
63
|
+
// checked in a hot path and the barrel is already the root of several import
|
|
64
|
+
// cycles.
|
|
65
|
+
import { applyPurl, ociPurl } from "../inventory/purl.js";
|
|
66
|
+
import { table } from "../inventory/table.js";
|
|
67
|
+
|
|
68
|
+
export { summarizeAiInventory } from "../inventory/aiInventory.js";
|
|
69
|
+
|
|
70
|
+
import {
|
|
71
|
+
enrichOSComponentsWithTrustData,
|
|
72
|
+
executeOsQuery,
|
|
73
|
+
getOSPackages,
|
|
74
|
+
getPluginToolComponents,
|
|
75
|
+
} from "../managers/binary.js";
|
|
76
|
+
import {
|
|
77
|
+
addSkippedSrcFiles,
|
|
78
|
+
exportArchive,
|
|
79
|
+
exportImage,
|
|
80
|
+
getPkgPathList,
|
|
81
|
+
parseImageName,
|
|
82
|
+
} from "../managers/docker.js";
|
|
83
|
+
import {
|
|
84
|
+
buildBomNSData,
|
|
85
|
+
createAndroidBom,
|
|
86
|
+
createBinaryBom,
|
|
87
|
+
createDefaultParentComponent,
|
|
88
|
+
dedupeBom,
|
|
89
|
+
determineParentComponent,
|
|
90
|
+
} from "./bomAssembly.js";
|
|
91
|
+
import {
|
|
92
|
+
createAsarBom,
|
|
93
|
+
createCaxaBom,
|
|
94
|
+
createChromeExtensionBom,
|
|
95
|
+
createNodejsBom,
|
|
96
|
+
createVscodeExtensionBom,
|
|
97
|
+
getDirectAiInventoryType,
|
|
98
|
+
} from "./jsBom.js";
|
|
99
|
+
import {
|
|
100
|
+
createJarBom,
|
|
101
|
+
createJavaBom,
|
|
102
|
+
GRADLE_CACHE_DIR,
|
|
103
|
+
SBT_CACHE_DIR,
|
|
104
|
+
} from "./jvmBom.js";
|
|
105
|
+
|
|
106
|
+
export {
|
|
107
|
+
createAndroidBom,
|
|
108
|
+
createBinaryBom,
|
|
109
|
+
dedupeBom,
|
|
110
|
+
listComponents,
|
|
111
|
+
} from "./bomAssembly.js";
|
|
112
|
+
export {
|
|
113
|
+
createAsarBom,
|
|
114
|
+
createCaxaBom,
|
|
115
|
+
createChromeExtensionBom,
|
|
116
|
+
createNodejsBom,
|
|
117
|
+
createVscodeExtensionBom,
|
|
118
|
+
} from "./jsBom.js";
|
|
119
|
+
export { createJarBom, createJavaBom } from "./jvmBom.js";
|
|
120
|
+
|
|
121
|
+
import {
|
|
122
|
+
createCloudBuildBom,
|
|
123
|
+
createCryptoCertsBom,
|
|
124
|
+
createCsharpBom,
|
|
125
|
+
createGitHubBom,
|
|
126
|
+
createHelmBom,
|
|
127
|
+
createJenkinsBom,
|
|
128
|
+
createPHPBom,
|
|
129
|
+
createPythonBom,
|
|
130
|
+
createRubyBom,
|
|
131
|
+
} from "./managedBom.js";
|
|
132
|
+
import {
|
|
133
|
+
createCargoCacheBom,
|
|
134
|
+
createClojureBom,
|
|
135
|
+
createCocoaBom,
|
|
136
|
+
createCppBom,
|
|
137
|
+
createDartBom,
|
|
138
|
+
createElixirBom,
|
|
139
|
+
createGleamBom,
|
|
140
|
+
createGoBom,
|
|
141
|
+
createHaskellBom,
|
|
142
|
+
createNixBom,
|
|
143
|
+
createRustBom,
|
|
144
|
+
createSwiftBom,
|
|
145
|
+
createZigBom,
|
|
146
|
+
getCargoCacheDir,
|
|
147
|
+
} from "./nativeBom.js";
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
createCloudBuildBom,
|
|
151
|
+
createCryptoCertsBom,
|
|
152
|
+
createCsharpBom,
|
|
153
|
+
createGitHubBom,
|
|
154
|
+
createHelmBom,
|
|
155
|
+
createJenkinsBom,
|
|
156
|
+
createPHPBom,
|
|
157
|
+
createPixiBom,
|
|
158
|
+
createPythonBom,
|
|
159
|
+
createRubyBom,
|
|
160
|
+
} from "./managedBom.js";
|
|
161
|
+
export {
|
|
162
|
+
createClojureBom,
|
|
163
|
+
createCocoaBom,
|
|
164
|
+
createCppBom,
|
|
165
|
+
createDartBom,
|
|
166
|
+
createElixirBom,
|
|
167
|
+
createGleamBom,
|
|
168
|
+
createGoBom,
|
|
169
|
+
createHaskellBom,
|
|
170
|
+
createNixBom,
|
|
171
|
+
createRustBom,
|
|
172
|
+
createSwiftBom,
|
|
173
|
+
createZigBom,
|
|
174
|
+
} from "./nativeBom.js";
|
|
175
|
+
|
|
176
|
+
const dirName = dirNameStr;
|
|
177
|
+
|
|
178
|
+
const isWin = _platform() === "win32";
|
|
179
|
+
|
|
180
|
+
let osQueries = {};
|
|
181
|
+
switch (_platform()) {
|
|
182
|
+
case "win32":
|
|
183
|
+
osQueries = JSON.parse(
|
|
184
|
+
readFileSync(join(dirName, "data", "queries-win.json"), "utf-8"),
|
|
185
|
+
);
|
|
186
|
+
break;
|
|
187
|
+
case "darwin":
|
|
188
|
+
osQueries = JSON.parse(
|
|
189
|
+
readFileSync(join(dirName, "data", "queries-darwin.json"), "utf-8"),
|
|
190
|
+
);
|
|
191
|
+
break;
|
|
192
|
+
default:
|
|
193
|
+
osQueries = JSON.parse(
|
|
194
|
+
readFileSync(join(dirName, "data", "queries.json"), "utf-8"),
|
|
195
|
+
);
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Function to create obom string for the current OS using osquery
|
|
201
|
+
*
|
|
202
|
+
* @param {string} _path to the project
|
|
203
|
+
* @param {Object} options Parse options from the cli
|
|
204
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
205
|
+
*/
|
|
206
|
+
export function createOSBom(_path, options) {
|
|
207
|
+
console.warn(
|
|
208
|
+
"About to generate OBOM for the current OS installation. This will take several minutes ...",
|
|
209
|
+
);
|
|
210
|
+
if (typeof process.getuid === "function" && process.getuid() !== 0) {
|
|
211
|
+
console.warn(
|
|
212
|
+
"Directories that are not readable by the current user will be skipped. Re-run with sudo for a complete OBOM.",
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
let pkgList = [];
|
|
216
|
+
let bomData = {};
|
|
217
|
+
let parentComponent = {};
|
|
218
|
+
let externalTools = getPluginToolComponents(["osquery"]);
|
|
219
|
+
for (const queryCategory of Object.keys(osQueries)) {
|
|
220
|
+
const queryObj = osQueries[queryCategory];
|
|
221
|
+
const results = executeOsQuery(queryObj.query);
|
|
222
|
+
const dlist = convertOSQueryResults(
|
|
223
|
+
queryCategory,
|
|
224
|
+
queryObj,
|
|
225
|
+
results,
|
|
226
|
+
false,
|
|
227
|
+
);
|
|
228
|
+
if (dlist?.length) {
|
|
229
|
+
if (!Object.keys(parentComponent).length) {
|
|
230
|
+
parentComponent = dlist.splice(0, 1)[0];
|
|
231
|
+
}
|
|
232
|
+
pkgList = pkgList.concat(
|
|
233
|
+
dlist.sort((a, b) => a.name.localeCompare(b.name)),
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
} // for
|
|
237
|
+
const hostTrustInventory = enrichOSComponentsWithTrustData(pkgList);
|
|
238
|
+
if (hostTrustInventory?.components?.length) {
|
|
239
|
+
pkgList = hostTrustInventory.components;
|
|
240
|
+
}
|
|
241
|
+
if (hostTrustInventory?.tools?.length) {
|
|
242
|
+
externalTools = externalTools.concat(hostTrustInventory.tools);
|
|
243
|
+
}
|
|
244
|
+
if (externalTools.length) {
|
|
245
|
+
options.tools = Array.from(
|
|
246
|
+
new Map(
|
|
247
|
+
externalTools.map((tool) => [tool["bom-ref"] || tool.name, tool]),
|
|
248
|
+
).values(),
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
if (pkgList.length) {
|
|
252
|
+
bomData = buildBomNSData(options, pkgList, "", {
|
|
253
|
+
src: "",
|
|
254
|
+
filename: "",
|
|
255
|
+
parentComponent,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
options.bomData = bomData;
|
|
259
|
+
options.multiProject = true;
|
|
260
|
+
options.installDeps = false;
|
|
261
|
+
options.parentComponent = parentComponent;
|
|
262
|
+
// Force the project type to os
|
|
263
|
+
options.projectType = ["os"];
|
|
264
|
+
options.lastWorkingDir = undefined;
|
|
265
|
+
options.allLayersExplodedDir = isWin ? "C:\\" : "";
|
|
266
|
+
const exportData = {
|
|
267
|
+
lastWorkingDir: undefined,
|
|
268
|
+
allLayersDir: options.allLayersExplodedDir,
|
|
269
|
+
allLayersExplodedDir: options.allLayersExplodedDir,
|
|
270
|
+
};
|
|
271
|
+
const pkgPathList = [];
|
|
272
|
+
if (options.deep) {
|
|
273
|
+
getPkgPathList(exportData, undefined);
|
|
274
|
+
}
|
|
275
|
+
return createMultiXBom(pkgPathList, options);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Function to create bom string for docker compose
|
|
280
|
+
*
|
|
281
|
+
* @param {string} path to the project
|
|
282
|
+
* @param {Object} options Parse options from the cli
|
|
283
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
284
|
+
*/
|
|
285
|
+
export async function createContainerSpecLikeBom(path, options) {
|
|
286
|
+
let services = [];
|
|
287
|
+
const ociSpecs = [];
|
|
288
|
+
let components = [];
|
|
289
|
+
let parentComponent = {};
|
|
290
|
+
let dependencies = [];
|
|
291
|
+
const doneimages = [];
|
|
292
|
+
const skippedImageSrcs = [];
|
|
293
|
+
const doneservices = [];
|
|
294
|
+
const origProjectType = options.projectType;
|
|
295
|
+
let dcFiles = getAllFiles(
|
|
296
|
+
path,
|
|
297
|
+
`${options.multiProject ? "**/" : ""}*.yml`,
|
|
298
|
+
options,
|
|
299
|
+
);
|
|
300
|
+
const dfFiles = getAllFiles(
|
|
301
|
+
path,
|
|
302
|
+
`${options.multiProject ? "**/" : ""}*Dockerfile*`,
|
|
303
|
+
options,
|
|
304
|
+
);
|
|
305
|
+
const bbPipelineFiles = getAllFiles(
|
|
306
|
+
path,
|
|
307
|
+
`${options.multiProject ? "**/" : ""}bitbucket-pipelines.yml`,
|
|
308
|
+
options,
|
|
309
|
+
);
|
|
310
|
+
const cfFiles = getAllFiles(
|
|
311
|
+
path,
|
|
312
|
+
`${options.multiProject ? "**/" : ""}*Containerfile*`,
|
|
313
|
+
options,
|
|
314
|
+
);
|
|
315
|
+
const yamlFiles = getAllFiles(
|
|
316
|
+
path,
|
|
317
|
+
`${options.multiProject ? "**/" : ""}*.yaml`,
|
|
318
|
+
options,
|
|
319
|
+
);
|
|
320
|
+
let oapiFiles = getAllFiles(
|
|
321
|
+
path,
|
|
322
|
+
`${options.multiProject ? "**/" : ""}open*.json`,
|
|
323
|
+
options,
|
|
324
|
+
);
|
|
325
|
+
const oapiYamlFiles = getAllFiles(
|
|
326
|
+
path,
|
|
327
|
+
`${options.multiProject ? "**/" : ""}open*.yaml`,
|
|
328
|
+
options,
|
|
329
|
+
);
|
|
330
|
+
if (oapiYamlFiles?.length) {
|
|
331
|
+
oapiFiles = oapiFiles.concat(oapiYamlFiles);
|
|
332
|
+
}
|
|
333
|
+
if (yamlFiles.length) {
|
|
334
|
+
dcFiles = dcFiles.concat(yamlFiles);
|
|
335
|
+
}
|
|
336
|
+
// Privado.ai json files
|
|
337
|
+
const privadoFiles = getAllFiles(path, ".privado/" + "*.json", options);
|
|
338
|
+
|
|
339
|
+
// Parse yaml manifest files, dockerfiles, containerfiles or bitbucket pipeline files
|
|
340
|
+
if (
|
|
341
|
+
dcFiles.length ||
|
|
342
|
+
dfFiles.length ||
|
|
343
|
+
cfFiles.length ||
|
|
344
|
+
bbPipelineFiles.length
|
|
345
|
+
) {
|
|
346
|
+
for (const f of [...dcFiles, ...dfFiles, ...cfFiles, ...bbPipelineFiles]) {
|
|
347
|
+
if (DEBUG_MODE) {
|
|
348
|
+
console.log(`Parsing ${f}`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const dData = readFileSync(f, { encoding: "utf-8" });
|
|
352
|
+
let imgList = [];
|
|
353
|
+
// parse yaml manifest files
|
|
354
|
+
if (f.endsWith("bitbucket-pipelines.yml")) {
|
|
355
|
+
imgList = parseBitbucketPipelinesFile(dData);
|
|
356
|
+
} else if (f.endsWith(".yml") || f.endsWith(".yaml")) {
|
|
357
|
+
imgList = parseContainerSpecData(dData);
|
|
358
|
+
} else {
|
|
359
|
+
imgList = parseContainerFile(dData);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (imgList?.length) {
|
|
363
|
+
if (DEBUG_MODE) {
|
|
364
|
+
console.log("Images identified in", f, "are", imgList);
|
|
365
|
+
}
|
|
366
|
+
for (const img of imgList) {
|
|
367
|
+
const commonProperties = [
|
|
368
|
+
{
|
|
369
|
+
name: "internal:SrcFile",
|
|
370
|
+
value: f,
|
|
371
|
+
},
|
|
372
|
+
];
|
|
373
|
+
if (img.image) {
|
|
374
|
+
commonProperties.push({
|
|
375
|
+
name: "oci:SrcImage",
|
|
376
|
+
value: img.image,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
if (img.service) {
|
|
380
|
+
commonProperties.push({
|
|
381
|
+
name: "internal:ServiceName",
|
|
382
|
+
value: img.service,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// img could have .service, .ociSpec or .image
|
|
387
|
+
if (img.ociSpec) {
|
|
388
|
+
console.log(
|
|
389
|
+
`NOTE: ${img.ociSpec} needs to built using docker or podman and referred with a name to get included in this SBOM.`,
|
|
390
|
+
);
|
|
391
|
+
ociSpecs.push({
|
|
392
|
+
group: "",
|
|
393
|
+
name: img.ociSpec,
|
|
394
|
+
version: "latest",
|
|
395
|
+
properties: commonProperties,
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (img.service) {
|
|
399
|
+
let version = "latest";
|
|
400
|
+
let name = img.service;
|
|
401
|
+
if (img.service.includes(":")) {
|
|
402
|
+
const tmpA = img.service.split(":");
|
|
403
|
+
if (tmpA && tmpA.length === 2) {
|
|
404
|
+
name = tmpA[0];
|
|
405
|
+
version = tmpA[1];
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const servbomRef = `urn:service:${name}:${version}`;
|
|
409
|
+
if (!doneservices.includes(servbomRef)) {
|
|
410
|
+
services.push({
|
|
411
|
+
"bom-ref": servbomRef,
|
|
412
|
+
name: name,
|
|
413
|
+
version: version,
|
|
414
|
+
group: "",
|
|
415
|
+
properties: commonProperties,
|
|
416
|
+
});
|
|
417
|
+
doneservices.push(servbomRef);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (img.image) {
|
|
421
|
+
if (doneimages.includes(img.image)) {
|
|
422
|
+
if (DEBUG_MODE) {
|
|
423
|
+
console.log(
|
|
424
|
+
"Skipping image as it's already been processed",
|
|
425
|
+
img.image,
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
skippedImageSrcs.push({ image: img.image, src: f });
|
|
430
|
+
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
if (DEBUG_MODE) {
|
|
434
|
+
console.log(`Parsing image ${img.image}`);
|
|
435
|
+
}
|
|
436
|
+
const imageObj = parseImageName(img.image);
|
|
437
|
+
|
|
438
|
+
const pkg = {
|
|
439
|
+
name: imageObj.name,
|
|
440
|
+
group: imageObj.group,
|
|
441
|
+
version:
|
|
442
|
+
imageObj.tag ||
|
|
443
|
+
(imageObj.digest ? `sha256:${imageObj.digest}` : "latest"),
|
|
444
|
+
qualifiers: {},
|
|
445
|
+
properties: commonProperties,
|
|
446
|
+
type: "container",
|
|
447
|
+
};
|
|
448
|
+
if (imageObj.registry) {
|
|
449
|
+
// Skip adding repository_url if the registry or repo contains variables.
|
|
450
|
+
if (
|
|
451
|
+
imageObj.registry.includes("${") ||
|
|
452
|
+
imageObj.repo.includes("${")
|
|
453
|
+
) {
|
|
454
|
+
if (DEBUG_MODE) {
|
|
455
|
+
console.warn(
|
|
456
|
+
"Skipping adding repository_url qualifier as it contains variables, which are not yet supported",
|
|
457
|
+
img.image,
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
pkg["qualifiers"]["repository_url"] =
|
|
462
|
+
`${imageObj.registry}/${imageObj.repo}`;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (imageObj.platform) {
|
|
466
|
+
pkg["qualifiers"]["platform"] = imageObj.platform;
|
|
467
|
+
}
|
|
468
|
+
if (imageObj.tag) {
|
|
469
|
+
pkg["qualifiers"]["tag"] = imageObj.tag;
|
|
470
|
+
}
|
|
471
|
+
// Create an entry for the oci image
|
|
472
|
+
const imageBomData = buildBomNSData(options, [pkg], "oci", {
|
|
473
|
+
src: img.image,
|
|
474
|
+
filename: f,
|
|
475
|
+
nsMapping: {},
|
|
476
|
+
});
|
|
477
|
+
if (imageBomData?.bomJson?.components) {
|
|
478
|
+
components = components.concat(imageBomData.bomJson.components);
|
|
479
|
+
}
|
|
480
|
+
const bomData = await createBom(img.image, {
|
|
481
|
+
specVersion: options.specVersion,
|
|
482
|
+
projectType: ["oci"],
|
|
483
|
+
});
|
|
484
|
+
doneimages.push(img.image);
|
|
485
|
+
if (bomData) {
|
|
486
|
+
if (bomData.components?.length) {
|
|
487
|
+
// Inject properties
|
|
488
|
+
for (const co of bomData.components) {
|
|
489
|
+
co.properties = commonProperties;
|
|
490
|
+
}
|
|
491
|
+
components = components.concat(bomData.components);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
} // img.image
|
|
495
|
+
} // for img
|
|
496
|
+
}
|
|
497
|
+
} // for
|
|
498
|
+
|
|
499
|
+
// Add additional SrcFile property to skipped image components
|
|
500
|
+
addSkippedSrcFiles(skippedImageSrcs, components);
|
|
501
|
+
} // if
|
|
502
|
+
// Parse openapi files
|
|
503
|
+
if (oapiFiles.length) {
|
|
504
|
+
for (const af of oapiFiles) {
|
|
505
|
+
if (DEBUG_MODE) {
|
|
506
|
+
console.log(`Parsing ${af}`);
|
|
507
|
+
}
|
|
508
|
+
const oaData = readFileSync(af, { encoding: "utf-8" });
|
|
509
|
+
const servlist = parseOpenapiSpecData(oaData);
|
|
510
|
+
if (servlist?.length) {
|
|
511
|
+
// Inject SrcFile property
|
|
512
|
+
for (const se of servlist) {
|
|
513
|
+
se.properties = [
|
|
514
|
+
{
|
|
515
|
+
name: "internal:SrcFile",
|
|
516
|
+
value: af,
|
|
517
|
+
},
|
|
518
|
+
];
|
|
519
|
+
}
|
|
520
|
+
services = mergeServices(services, servlist);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
// Parse privado files
|
|
525
|
+
if (privadoFiles.length) {
|
|
526
|
+
console.log(
|
|
527
|
+
"Enriching your SBOM with information from privado.ai scan reports",
|
|
528
|
+
);
|
|
529
|
+
let rows = [["Classification", "Flow"]];
|
|
530
|
+
const config = {
|
|
531
|
+
header: {
|
|
532
|
+
alignment: "center",
|
|
533
|
+
content: "Data Privacy Insights from privado.ai",
|
|
534
|
+
},
|
|
535
|
+
columns: [{ width: 50 }, { width: 10 }],
|
|
536
|
+
};
|
|
537
|
+
for (const f of privadoFiles) {
|
|
538
|
+
if (DEBUG_MODE) {
|
|
539
|
+
console.log(`Parsing ${f}`);
|
|
540
|
+
}
|
|
541
|
+
const servlist = parsePrivadoFile(f);
|
|
542
|
+
services = mergeServices(services, servlist);
|
|
543
|
+
if (servlist.length) {
|
|
544
|
+
const aservice = servlist[0];
|
|
545
|
+
if (aservice.data) {
|
|
546
|
+
for (const d of aservice.data) {
|
|
547
|
+
rows.push([d.classification, d.flow]);
|
|
548
|
+
}
|
|
549
|
+
console.log(table(rows, config));
|
|
550
|
+
}
|
|
551
|
+
if (aservice.endpoints) {
|
|
552
|
+
rows = [["Leaky Endpoints"]];
|
|
553
|
+
for (const e of aservice.endpoints) {
|
|
554
|
+
rows.push([e]);
|
|
555
|
+
}
|
|
556
|
+
console.log(
|
|
557
|
+
table(rows, {
|
|
558
|
+
columnDefault: {
|
|
559
|
+
width: 50,
|
|
560
|
+
},
|
|
561
|
+
}),
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (origProjectType?.includes("universal")) {
|
|
568
|
+
// In case of universal, repeat to collect multiX Boms
|
|
569
|
+
const mbomData = await createMultiXBom(path, {
|
|
570
|
+
...options,
|
|
571
|
+
projectType: [],
|
|
572
|
+
multiProject: true,
|
|
573
|
+
excludeType: options.excludeType,
|
|
574
|
+
});
|
|
575
|
+
if (mbomData) {
|
|
576
|
+
if (mbomData.components?.length) {
|
|
577
|
+
components = components.concat(mbomData.components);
|
|
578
|
+
}
|
|
579
|
+
// We need to retain the parentComponent. See #527
|
|
580
|
+
// Parent component returned by multi X search is usually good
|
|
581
|
+
parentComponent = mbomData.parentComponent;
|
|
582
|
+
options.parentComponent = parentComponent;
|
|
583
|
+
if (mbomData.bomJson) {
|
|
584
|
+
if (mbomData.bomJson.dependencies) {
|
|
585
|
+
dependencies = mergeDependencies(
|
|
586
|
+
dependencies,
|
|
587
|
+
mbomData.bomJson.dependencies,
|
|
588
|
+
parentComponent,
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
if (mbomData.bomJson.services) {
|
|
592
|
+
services = mergeServices(services, mbomData.bomJson.services);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
if (DEBUG_MODE) {
|
|
596
|
+
console.log(
|
|
597
|
+
`Received ${components.length} unfiltered components ${dependencies.length} dependencies so far.`,
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
options.services = mergeServices([], services);
|
|
603
|
+
options.ociSpecs = ociSpecs;
|
|
604
|
+
return dedupeBom(options, components, parentComponent, dependencies);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Decide how many paths of a multi-path scan may be inspected at once.
|
|
609
|
+
*
|
|
610
|
+
* A container image contributes around twenty rootfs paths, each of which is
|
|
611
|
+
* offered to every ecosystem, so overlapping them shortens the scan. Two
|
|
612
|
+
* situations stay sequential. A single path has nothing to overlap. Dry run and
|
|
613
|
+
* debug mode narrate their progress through one activity context and one log,
|
|
614
|
+
* so their output describes the paths one at a time.
|
|
615
|
+
*
|
|
616
|
+
* The bound follows the processor count and stops at eight, matching the worker
|
|
617
|
+
* pool. Every path also resolves packages over the network, where requests are
|
|
618
|
+
* already batched per host, so a registry sees the product of the two bounds.
|
|
619
|
+
*
|
|
620
|
+
* @param {string[]} pathList Paths about to be scanned
|
|
621
|
+
* @returns {number} Number of paths to scan at once
|
|
622
|
+
*/
|
|
623
|
+
function pathScanConcurrency(pathList) {
|
|
624
|
+
if (!pathList || pathList.length < 2 || isDryRun || DEBUG_MODE) {
|
|
625
|
+
return 1;
|
|
626
|
+
}
|
|
627
|
+
const defaultLimit = Math.min(availableParallelism() || 4, 8);
|
|
628
|
+
const configured = Number.parseInt(
|
|
629
|
+
readEnvironmentVariable("CDXGEN_MAX_PATH_SCANS") || String(defaultLimit),
|
|
630
|
+
10,
|
|
631
|
+
);
|
|
632
|
+
const limit =
|
|
633
|
+
Number.isNaN(configured) || configured < 1 ? defaultLimit : configured;
|
|
634
|
+
return Math.min(pathList.length, limit);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Function to create bom string for all languages
|
|
639
|
+
*
|
|
640
|
+
* @param {string[]} pathList list of to the project
|
|
641
|
+
* @param {Object} options Parse options from the cli
|
|
642
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
643
|
+
*/
|
|
644
|
+
/**
|
|
645
|
+
* Join non-zero counts into a phase summary.
|
|
646
|
+
*
|
|
647
|
+
* Each entry carries its own plural form rather than having one appended, so
|
|
648
|
+
* nouns like "shared library" read correctly.
|
|
649
|
+
*
|
|
650
|
+
* @param {Array<[number, string, string]>} entries Count, singular, and plural
|
|
651
|
+
* @returns {string} Summary such as "412 OS packages, 3 services"
|
|
652
|
+
*/
|
|
653
|
+
export function summarizeCounts(entries) {
|
|
654
|
+
return entries
|
|
655
|
+
.filter(([count]) => count > 0)
|
|
656
|
+
.map(
|
|
657
|
+
([count, singular, plural]) =>
|
|
658
|
+
`${count} ${count === 1 ? singular : plural}`,
|
|
659
|
+
)
|
|
660
|
+
.join(", ");
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Summarize components by purl type, so a scan reports "412 npm, 88 pypi"
|
|
665
|
+
* rather than an anonymous total.
|
|
666
|
+
*
|
|
667
|
+
* @param {object[]} components Components carrying purls
|
|
668
|
+
* @returns {string} Comma-separated counts, busiest type first
|
|
669
|
+
*/
|
|
670
|
+
export function summarizePurlTypes(components) {
|
|
671
|
+
const counts = new Map();
|
|
672
|
+
for (const component of components) {
|
|
673
|
+
const purlType = `${component?.purl || ""}`.split("/")[0].slice(4);
|
|
674
|
+
const key = purlType || component?.type || "component";
|
|
675
|
+
counts.set(key, (counts.get(key) || 0) + 1);
|
|
676
|
+
}
|
|
677
|
+
return [...counts.entries()]
|
|
678
|
+
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
|
679
|
+
.map(([type, count]) => `${count} ${type}`)
|
|
680
|
+
.join(", ");
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Generates BOMs across multiple project types and/or paths, then merges and
|
|
685
|
+
* deduplicates the results into a single BOM namespace data object. Handles
|
|
686
|
+
* OCI/container inventory, per-path scans, formulation accumulation, and
|
|
687
|
+
* parent-component reconciliation.
|
|
688
|
+
*
|
|
689
|
+
* @param {string|string[]} pathList Comma-separated string or array of paths
|
|
690
|
+
* @param {object} options CLI options
|
|
691
|
+
* @returns {Promise<object>} Promise resolving to a deduplicated BOM namespace
|
|
692
|
+
* data object (components, dependencies, bomJson, parentComponent, etc.)
|
|
693
|
+
*/
|
|
694
|
+
export async function createMultiXBom(pathList, options) {
|
|
695
|
+
let components = [];
|
|
696
|
+
let dependencies = [];
|
|
697
|
+
let bomData;
|
|
698
|
+
let formulationList = [];
|
|
699
|
+
let parentComponent = determineParentComponent(options) || {};
|
|
700
|
+
let parentSubComponents = [];
|
|
701
|
+
const setProjectTypeActivityContext = (projectType, sourcePath) => {
|
|
702
|
+
setActivityContext({
|
|
703
|
+
projectType,
|
|
704
|
+
sourcePath,
|
|
705
|
+
});
|
|
706
|
+
};
|
|
707
|
+
options.createMultiXBom = true;
|
|
708
|
+
// Convert single path to an array
|
|
709
|
+
if (!Array.isArray(pathList)) {
|
|
710
|
+
pathList = pathList.split(",");
|
|
711
|
+
}
|
|
712
|
+
if (
|
|
713
|
+
options.projectType &&
|
|
714
|
+
hasAnyProjectType(["oci"], options, false) &&
|
|
715
|
+
options.allLayersExplodedDir
|
|
716
|
+
) {
|
|
717
|
+
const osPhase = ui.phase("Inventorying OS packages");
|
|
718
|
+
const {
|
|
719
|
+
osPackages,
|
|
720
|
+
osPackageFiles,
|
|
721
|
+
dependenciesList,
|
|
722
|
+
allTypes,
|
|
723
|
+
bundledSdks,
|
|
724
|
+
bundledRuntimes,
|
|
725
|
+
binPaths,
|
|
726
|
+
executables,
|
|
727
|
+
sharedLibs,
|
|
728
|
+
services,
|
|
729
|
+
tools,
|
|
730
|
+
} = await getOSPackages(
|
|
731
|
+
options.allLayersExplodedDir,
|
|
732
|
+
options.exportData?.inspectData?.Config,
|
|
733
|
+
options,
|
|
734
|
+
);
|
|
735
|
+
osPhase.succeed(
|
|
736
|
+
summarizeCounts([
|
|
737
|
+
[osPackages.length, "OS package", "OS packages"],
|
|
738
|
+
[osPackageFiles?.length, "package-owned file", "package-owned files"],
|
|
739
|
+
[executables?.length, "executable", "executables"],
|
|
740
|
+
[sharedLibs?.length, "shared library", "shared libraries"],
|
|
741
|
+
[services?.length, "service", "services"],
|
|
742
|
+
]),
|
|
743
|
+
);
|
|
744
|
+
// TODO: Need to test these with docker-compose type where multiple images could have different values.
|
|
745
|
+
// This is also clearly misusing options, which must become immutable at some point.
|
|
746
|
+
options.bundledSdks = bundledSdks;
|
|
747
|
+
options.bundledRuntimes = bundledRuntimes;
|
|
748
|
+
options.binPaths = binPaths;
|
|
749
|
+
options.unpackagedExecutableCount = executables?.length || 0;
|
|
750
|
+
options.unpackagedSharedLibraryCount = sharedLibs?.length || 0;
|
|
751
|
+
if (DEBUG_MODE) {
|
|
752
|
+
console.log(
|
|
753
|
+
`**OS**: Found ${osPackages.length} OS packages, ${osPackageFiles?.length} package-owned files, ${executables?.length} unpackaged executables, ${sharedLibs.length} unpackaged shared libraries, and ${services?.length || 0} packaged services at ${options.allLayersExplodedDir}`,
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
if (osPackages.length) {
|
|
757
|
+
thoughtLog(
|
|
758
|
+
`I found ${osPackages.length} OS packages, ${osPackageFiles?.length || 0} package-owned files, and ${services?.length || 0} packaged services at ${options.allLayersExplodedDir}`,
|
|
759
|
+
);
|
|
760
|
+
} else if (executables?.length || sharedLibs?.length) {
|
|
761
|
+
thoughtLog(
|
|
762
|
+
`I couldn't find any OS packages, but I found ${executables.length} executables and ${sharedLibs.length} shared libraries at ${options.allLayersExplodedDir}. Perhaps the binary plugin wasn't available, or the architecture is unsupported.`,
|
|
763
|
+
);
|
|
764
|
+
} else {
|
|
765
|
+
thoughtLog(
|
|
766
|
+
`I couldn't find any OS packages at ${options.allLayersExplodedDir}. Perhaps the binary plugin wasn't available, or the architecture is unsupported.`,
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
if (allTypes?.length) {
|
|
770
|
+
options.allOSComponentTypes = allTypes;
|
|
771
|
+
}
|
|
772
|
+
if (tools?.length) {
|
|
773
|
+
options.tools = (
|
|
774
|
+
Array.isArray(options.tools)
|
|
775
|
+
? options.tools
|
|
776
|
+
: options.tools?.components || []
|
|
777
|
+
).concat(tools);
|
|
778
|
+
}
|
|
779
|
+
components = components.concat(osPackages);
|
|
780
|
+
components = components.concat(osPackageFiles || []);
|
|
781
|
+
components = components.concat(executables);
|
|
782
|
+
components = components.concat(sharedLibs);
|
|
783
|
+
if (dependenciesList?.length) {
|
|
784
|
+
dependencies = mergeDependencies(dependencies, dependenciesList);
|
|
785
|
+
}
|
|
786
|
+
if (services?.length) {
|
|
787
|
+
options.services = mergeServices(options.services || [], services);
|
|
788
|
+
}
|
|
789
|
+
if (parentComponent && Object.keys(parentComponent).length) {
|
|
790
|
+
// Make the parent oci image depend on all os components
|
|
791
|
+
const parentDependsOn = new Set(
|
|
792
|
+
osPackages.concat(osPackageFiles || []).map((p) => p["bom-ref"]),
|
|
793
|
+
);
|
|
794
|
+
dependencies.splice(0, 0, {
|
|
795
|
+
ref: parentComponent["bom-ref"],
|
|
796
|
+
dependsOn: Array.from(parentDependsOn).sort(),
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
if (hasAnyProjectType(["os"], options, false) && options.bomData) {
|
|
801
|
+
bomData = options.bomData;
|
|
802
|
+
if (bomData?.bomJson?.components) {
|
|
803
|
+
if (DEBUG_MODE) {
|
|
804
|
+
console.log(`Found ${bomData.bomJson.components.length} OS components`);
|
|
805
|
+
}
|
|
806
|
+
if (bomData.bomJson.components.length) {
|
|
807
|
+
thoughtLog(
|
|
808
|
+
`I found ${bomData.bomJson.components.length} OS packages 😎.`,
|
|
809
|
+
);
|
|
810
|
+
}
|
|
811
|
+
components = components.concat(bomData.bomJson.components);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
const sharedOptions = options;
|
|
815
|
+
// The exploded image layers are written once by the extractor and only read
|
|
816
|
+
// from here on, so repeated walks of them can share one view of the tree.
|
|
817
|
+
setDirWalkCacheRoot(options.allLayersExplodedDir);
|
|
818
|
+
const scanOnePath = async (path) => {
|
|
819
|
+
// Each path accumulates into its own lists and its own view of options, so
|
|
820
|
+
// that legs which record a parent component or a tool cannot overwrite
|
|
821
|
+
// another path's. The lists are merged below in pathList order.
|
|
822
|
+
const options = { ...sharedOptions };
|
|
823
|
+
let bomData;
|
|
824
|
+
let components = [];
|
|
825
|
+
let dependencies = [];
|
|
826
|
+
let parentSubComponents = [];
|
|
827
|
+
setActivityContext({
|
|
828
|
+
projectType: Array.isArray(options.projectType)
|
|
829
|
+
? options.projectType.join(",")
|
|
830
|
+
: options.projectType,
|
|
831
|
+
sourcePath: path,
|
|
832
|
+
});
|
|
833
|
+
recordActivity({
|
|
834
|
+
kind: "read",
|
|
835
|
+
reason:
|
|
836
|
+
"Scanning project path for supported languages and package managers.",
|
|
837
|
+
status: "completed",
|
|
838
|
+
target: path,
|
|
839
|
+
});
|
|
840
|
+
if (DEBUG_MODE) {
|
|
841
|
+
console.log("Scanning", path);
|
|
842
|
+
}
|
|
843
|
+
if (pathList.length > 2) {
|
|
844
|
+
thoughtLog(`Let's thoroughly check the path ${path}.`);
|
|
845
|
+
}
|
|
846
|
+
// Node.js and AI inventory
|
|
847
|
+
if (
|
|
848
|
+
hasAnyProjectType(["oci", "js"], options) ||
|
|
849
|
+
hasAnyProjectType(["mcp", "ai-skill", "ai"], options) ||
|
|
850
|
+
getDirectAiInventoryType(path, options)
|
|
851
|
+
) {
|
|
852
|
+
const exactAiInventoryType = getDirectAiInventoryType(path, options);
|
|
853
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
854
|
+
if (exactAiInventoryType === "mcp") {
|
|
855
|
+
thoughtLog(
|
|
856
|
+
"**MCP**: Looking for MCP services, MCP configs, and related AI control-plane artifacts.",
|
|
857
|
+
);
|
|
858
|
+
} else if (exactAiInventoryType === "ai") {
|
|
859
|
+
thoughtLog(
|
|
860
|
+
"**AI-BOM**: Looking for AI models, direct model metadata, pedigree, quantization, and operator-facing AI context.",
|
|
861
|
+
);
|
|
862
|
+
} else if (exactAiInventoryType === "ai-skill") {
|
|
863
|
+
thoughtLog(
|
|
864
|
+
"**AI-SKILL**: Looking for AI instruction, skill, and agent-definition files that can influence build or release flows.",
|
|
865
|
+
);
|
|
866
|
+
} else {
|
|
867
|
+
thoughtLog(
|
|
868
|
+
"**JS**: Now looking for JavaScript projects (npm, yarn, pnpm) and files.",
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
setProjectTypeActivityContext(exactAiInventoryType || "js", path);
|
|
873
|
+
bomData = await createNodejsBom(path, options);
|
|
874
|
+
if (bomData?.bomJson?.components?.length) {
|
|
875
|
+
if (exactAiInventoryType) {
|
|
876
|
+
thoughtLog(
|
|
877
|
+
`I found ${bomData.bomJson.components.length} ${exactAiInventoryType} component(s). Let's keep looking.`,
|
|
878
|
+
);
|
|
879
|
+
} else {
|
|
880
|
+
thoughtLog(
|
|
881
|
+
`I found ${bomData.bomJson.components.length} npm packages. Let's keep looking.`,
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
if (DEBUG_MODE) {
|
|
885
|
+
console.log(
|
|
886
|
+
`Found ${bomData.bomJson.components.length} ${exactAiInventoryType || "npm"} components at ${path}`,
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
components = components.concat(bomData.bomJson.components);
|
|
890
|
+
dependencies = mergeDependencies(
|
|
891
|
+
dependencies,
|
|
892
|
+
bomData.bomJson.dependencies,
|
|
893
|
+
);
|
|
894
|
+
if (bomData?.bomJson?.services?.length) {
|
|
895
|
+
options.services = mergeServices(
|
|
896
|
+
options.services || [],
|
|
897
|
+
bomData.bomJson.services,
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
if (
|
|
901
|
+
bomData.parentComponent &&
|
|
902
|
+
Object.keys(bomData.parentComponent).length
|
|
903
|
+
) {
|
|
904
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
905
|
+
}
|
|
906
|
+
// Retain metadata.component.components
|
|
907
|
+
if (bomData.parentComponent.components?.length) {
|
|
908
|
+
parentSubComponents = parentSubComponents.concat(
|
|
909
|
+
bomData.parentComponent.components,
|
|
910
|
+
);
|
|
911
|
+
delete bomData.parentComponent.components;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
// Java
|
|
916
|
+
if (hasAnyProjectType(["oci", "java"], options)) {
|
|
917
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
918
|
+
thoughtLog(
|
|
919
|
+
"**JAVA**: Looking for Java projects (e.g., Maven, Gradle, SBT). I hope all configurations—from Java version to individual build settings—are correctly aligned.",
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
setProjectTypeActivityContext("java", path);
|
|
923
|
+
bomData = await createJavaBom(path, options);
|
|
924
|
+
if (bomData?.bomJson?.components?.length) {
|
|
925
|
+
thoughtLog(
|
|
926
|
+
`I found ${bomData.bomJson.components.length} java packages.`,
|
|
927
|
+
);
|
|
928
|
+
if (DEBUG_MODE) {
|
|
929
|
+
console.log(
|
|
930
|
+
`Found ${bomData.bomJson.components.length} java packages at ${path}`,
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
components = components.concat(bomData.bomJson.components);
|
|
934
|
+
dependencies = mergeDependencies(
|
|
935
|
+
dependencies,
|
|
936
|
+
bomData.bomJson.dependencies,
|
|
937
|
+
);
|
|
938
|
+
if (
|
|
939
|
+
bomData.parentComponent &&
|
|
940
|
+
Object.keys(bomData.parentComponent).length
|
|
941
|
+
) {
|
|
942
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
943
|
+
}
|
|
944
|
+
// Retain metadata.component.components, but add duplicates to the list of current components
|
|
945
|
+
// and removing them from metadata.component.components -- the components are merged later
|
|
946
|
+
if (bomData.parentComponent.components?.length) {
|
|
947
|
+
let bomSubComponents = bomData.parentComponent.components;
|
|
948
|
+
if (
|
|
949
|
+
!["false", "0"].includes(
|
|
950
|
+
readEnvironmentVariable("GRADLE_RESOLVE_FROM_NODE"),
|
|
951
|
+
)
|
|
952
|
+
) {
|
|
953
|
+
thoughtLog(
|
|
954
|
+
"Wait, the user wants me to resolve gradle projects from npm.",
|
|
955
|
+
);
|
|
956
|
+
const allRefs = components.map((c) => c["bom-ref"]);
|
|
957
|
+
const duplicateComponents = bomSubComponents.filter((c) =>
|
|
958
|
+
allRefs.includes(c["bom-ref"]),
|
|
959
|
+
);
|
|
960
|
+
components = components.concat(duplicateComponents);
|
|
961
|
+
const duplicateComponentRefs = duplicateComponents.map(
|
|
962
|
+
(c) => c["bom-ref"],
|
|
963
|
+
);
|
|
964
|
+
bomSubComponents = bomSubComponents.filter(
|
|
965
|
+
(c) => !duplicateComponentRefs.includes(c["bom-ref"]),
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
parentSubComponents = parentSubComponents.concat(bomSubComponents);
|
|
969
|
+
delete bomData.parentComponent.components;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
if (hasAnyProjectType(["oci", "py"], options)) {
|
|
974
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
975
|
+
thoughtLog(
|
|
976
|
+
"**PYTHON**: Looking for Python projects with package managers such as pip, poetry, uv, etc. Wish me good luck!",
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
if (
|
|
980
|
+
readEnvironmentVariable("CDXGEN_IN_CONTAINER") !== "true" &&
|
|
981
|
+
pathList.length <= 2
|
|
982
|
+
) {
|
|
983
|
+
thoughtLog(
|
|
984
|
+
"I'm running in a non-container environment. Let's hope the correct build tools are available ✌️.",
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
setProjectTypeActivityContext("py", path);
|
|
988
|
+
bomData = await createPythonBom(path, options);
|
|
989
|
+
if (bomData?.bomJson?.components?.length) {
|
|
990
|
+
thoughtLog(
|
|
991
|
+
`I found ${bomData.bomJson.components.length} python packages.`,
|
|
992
|
+
);
|
|
993
|
+
if (DEBUG_MODE) {
|
|
994
|
+
console.log(
|
|
995
|
+
`Found ${bomData.bomJson.components.length} python packages at ${path}`,
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
components = components.concat(bomData.bomJson.components);
|
|
999
|
+
dependencies = mergeDependencies(
|
|
1000
|
+
dependencies,
|
|
1001
|
+
bomData.bomJson.dependencies,
|
|
1002
|
+
);
|
|
1003
|
+
if (
|
|
1004
|
+
bomData.parentComponent &&
|
|
1005
|
+
Object.keys(bomData.parentComponent).length
|
|
1006
|
+
) {
|
|
1007
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
if (bomData?.formulationList?.length) {
|
|
1011
|
+
formulationList = formulationList.concat(bomData.formulationList);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (hasAnyProjectType(["oci", "go"], options)) {
|
|
1015
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1016
|
+
thoughtLog(
|
|
1017
|
+
"**GO**: Looking for go projects. I need to be cautious about purl namespaces and potential failures with the 'go list' command.",
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
setProjectTypeActivityContext("go", path);
|
|
1021
|
+
bomData = await createGoBom(path, options);
|
|
1022
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1023
|
+
thoughtLog(`I found ${bomData.bomJson.components.length} go packages.`);
|
|
1024
|
+
if (DEBUG_MODE) {
|
|
1025
|
+
console.log(
|
|
1026
|
+
`Found ${bomData.bomJson.components.length} go packages at ${path}`,
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
components = components.concat(bomData.bomJson.components);
|
|
1030
|
+
dependencies = mergeDependencies(
|
|
1031
|
+
dependencies,
|
|
1032
|
+
bomData.bomJson.dependencies,
|
|
1033
|
+
);
|
|
1034
|
+
if (
|
|
1035
|
+
bomData.parentComponent &&
|
|
1036
|
+
Object.keys(bomData.parentComponent).length
|
|
1037
|
+
) {
|
|
1038
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
if (hasAnyProjectType(["oci", "rust"], options)) {
|
|
1043
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1044
|
+
thoughtLog(
|
|
1045
|
+
"**RUST**: Let's search for Cargo/Rust projects. Should I warn the user that we don't support Cargo 'features' and native dependencies, which may lead to both false positives and false negatives? 🤔?",
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
setProjectTypeActivityContext("rust", path);
|
|
1049
|
+
bomData = await createRustBom(path, options);
|
|
1050
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1051
|
+
thoughtLog(
|
|
1052
|
+
`I found ${bomData.bomJson.components.length} rust packages.`,
|
|
1053
|
+
);
|
|
1054
|
+
if (DEBUG_MODE) {
|
|
1055
|
+
console.log(
|
|
1056
|
+
`Found ${bomData.bomJson.components.length} rust packages at ${path}`,
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
components = components.concat(bomData.bomJson.components);
|
|
1060
|
+
dependencies = mergeDependencies(
|
|
1061
|
+
dependencies,
|
|
1062
|
+
bomData.bomJson.dependencies,
|
|
1063
|
+
);
|
|
1064
|
+
if (
|
|
1065
|
+
bomData.parentComponent &&
|
|
1066
|
+
Object.keys(bomData.parentComponent).length
|
|
1067
|
+
) {
|
|
1068
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1069
|
+
}
|
|
1070
|
+
// Retain metadata.component.components
|
|
1071
|
+
if (bomData.parentComponent?.components?.length) {
|
|
1072
|
+
parentSubComponents = parentSubComponents.concat(
|
|
1073
|
+
bomData.parentComponent.components,
|
|
1074
|
+
);
|
|
1075
|
+
delete bomData.parentComponent.components;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
if (hasAnyProjectType(["oci", "php"], options)) {
|
|
1080
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1081
|
+
thoughtLog(
|
|
1082
|
+
"**PHP**: About to search for Composer-based projects. I hope lock files are available; otherwise, the 'composer install' command might fail for various reasons.",
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
setProjectTypeActivityContext("php", path);
|
|
1086
|
+
bomData = createPHPBom(path, options);
|
|
1087
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1088
|
+
thoughtLog(
|
|
1089
|
+
`I found ${bomData.bomJson.components.length} php packages.`,
|
|
1090
|
+
);
|
|
1091
|
+
if (DEBUG_MODE) {
|
|
1092
|
+
console.log(
|
|
1093
|
+
`Found ${bomData.bomJson.components.length} php packages at ${path}`,
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1096
|
+
components = components.concat(bomData.bomJson.components);
|
|
1097
|
+
dependencies = mergeDependencies(
|
|
1098
|
+
dependencies,
|
|
1099
|
+
bomData.bomJson.dependencies,
|
|
1100
|
+
);
|
|
1101
|
+
if (
|
|
1102
|
+
bomData.parentComponent &&
|
|
1103
|
+
Object.keys(bomData.parentComponent).length
|
|
1104
|
+
) {
|
|
1105
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1106
|
+
}
|
|
1107
|
+
// Retain metadata.component.components
|
|
1108
|
+
if (bomData.parentComponent?.components?.length) {
|
|
1109
|
+
parentSubComponents = parentSubComponents.concat(
|
|
1110
|
+
bomData.parentComponent.components,
|
|
1111
|
+
);
|
|
1112
|
+
delete bomData.parentComponent.components;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
if (hasAnyProjectType(["oci", "ruby"], options)) {
|
|
1117
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1118
|
+
thoughtLog(
|
|
1119
|
+
"**RUBY**: Are there any Ruby projects in this path? There's only one way to know.",
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
setProjectTypeActivityContext("ruby", path);
|
|
1123
|
+
bomData = await createRubyBom(path, options);
|
|
1124
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1125
|
+
thoughtLog(
|
|
1126
|
+
`We got ${bomData.bomJson.components.length} ruby packages.`,
|
|
1127
|
+
);
|
|
1128
|
+
if (DEBUG_MODE) {
|
|
1129
|
+
console.log(
|
|
1130
|
+
`Found ${bomData.bomJson.components.length} ruby packages at ${path}`,
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
components = components.concat(bomData.bomJson.components);
|
|
1134
|
+
dependencies = mergeDependencies(
|
|
1135
|
+
dependencies,
|
|
1136
|
+
bomData.bomJson.dependencies,
|
|
1137
|
+
bomData.parentComponent,
|
|
1138
|
+
);
|
|
1139
|
+
if (
|
|
1140
|
+
bomData.parentComponent &&
|
|
1141
|
+
Object.keys(bomData.parentComponent).length
|
|
1142
|
+
) {
|
|
1143
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1144
|
+
}
|
|
1145
|
+
// Retain metadata.component.components
|
|
1146
|
+
if (bomData.parentComponent?.components?.length) {
|
|
1147
|
+
parentSubComponents = parentSubComponents.concat(
|
|
1148
|
+
bomData.parentComponent.components,
|
|
1149
|
+
);
|
|
1150
|
+
delete bomData.parentComponent.components;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
if (hasAnyProjectType(["oci", "csharp"], options)) {
|
|
1155
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1156
|
+
thoughtLog("**CSHARP**: What about csharp and fsharp projects?");
|
|
1157
|
+
}
|
|
1158
|
+
setProjectTypeActivityContext("csharp", path);
|
|
1159
|
+
bomData = await createCsharpBom(path, options);
|
|
1160
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1161
|
+
thoughtLog(
|
|
1162
|
+
`There are ${bomData.bomJson.components.length} csharp packages.`,
|
|
1163
|
+
);
|
|
1164
|
+
if (DEBUG_MODE) {
|
|
1165
|
+
console.log(
|
|
1166
|
+
`Found ${bomData.bomJson.components.length} csharp packages at ${path}`,
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
components = components.concat(bomData.bomJson.components);
|
|
1170
|
+
dependencies = mergeDependencies(
|
|
1171
|
+
dependencies,
|
|
1172
|
+
bomData.bomJson.dependencies,
|
|
1173
|
+
);
|
|
1174
|
+
if (
|
|
1175
|
+
bomData.parentComponent &&
|
|
1176
|
+
Object.keys(bomData.parentComponent).length
|
|
1177
|
+
) {
|
|
1178
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1179
|
+
}
|
|
1180
|
+
// Retain metadata.component.components
|
|
1181
|
+
if (bomData.parentComponent?.components?.length) {
|
|
1182
|
+
parentSubComponents = parentSubComponents.concat(
|
|
1183
|
+
bomData.parentComponent.components,
|
|
1184
|
+
);
|
|
1185
|
+
delete bomData.parentComponent.components;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
if (hasAnyProjectType(["oci", "dart"], options)) {
|
|
1190
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1191
|
+
thoughtLog(
|
|
1192
|
+
"**DART**: Looking for Dart projects. These are rare ones. Should I inform the user that they can pass the types argument via the command-line to speed things up?",
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
setProjectTypeActivityContext("dart", path);
|
|
1196
|
+
bomData = await createDartBom(path, options);
|
|
1197
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1198
|
+
thoughtLog(
|
|
1199
|
+
`I found ${bomData.bomJson.components.length} pub packages.`,
|
|
1200
|
+
);
|
|
1201
|
+
if (DEBUG_MODE) {
|
|
1202
|
+
console.log(
|
|
1203
|
+
`Found ${bomData.bomJson.components.length} pub packages at ${path}`,
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
components = components.concat(bomData.bomJson.components);
|
|
1207
|
+
dependencies = mergeDependencies(
|
|
1208
|
+
dependencies,
|
|
1209
|
+
bomData.bomJson.dependencies,
|
|
1210
|
+
);
|
|
1211
|
+
if (
|
|
1212
|
+
bomData.parentComponent &&
|
|
1213
|
+
Object.keys(bomData.parentComponent).length
|
|
1214
|
+
) {
|
|
1215
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
if (hasAnyProjectType(["oci", "haskell"], options)) {
|
|
1220
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1221
|
+
thoughtLog(
|
|
1222
|
+
"**HASKELL**: Looking for Haskell projects. They're rarely encountered.",
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
setProjectTypeActivityContext("haskell", path);
|
|
1226
|
+
bomData = createHaskellBom(path, options);
|
|
1227
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1228
|
+
thoughtLog(
|
|
1229
|
+
`I found ${bomData.bomJson.components.length} hackage packages.`,
|
|
1230
|
+
);
|
|
1231
|
+
if (DEBUG_MODE) {
|
|
1232
|
+
console.log(
|
|
1233
|
+
`Found ${bomData.bomJson.components.length} hackage packages at ${path}`,
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
components = components.concat(bomData.bomJson.components);
|
|
1237
|
+
dependencies = mergeDependencies(
|
|
1238
|
+
dependencies,
|
|
1239
|
+
bomData.bomJson.dependencies,
|
|
1240
|
+
);
|
|
1241
|
+
if (
|
|
1242
|
+
bomData.parentComponent &&
|
|
1243
|
+
Object.keys(bomData.parentComponent).length
|
|
1244
|
+
) {
|
|
1245
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
if (hasAnyProjectType(["oci", "elixir"], options)) {
|
|
1250
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1251
|
+
thoughtLog(
|
|
1252
|
+
"**ELIXIR**: Looking for Elixir projects—they're quite rare as well.",
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
setProjectTypeActivityContext("elixir", path);
|
|
1256
|
+
bomData = createElixirBom(path, options);
|
|
1257
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1258
|
+
thoughtLog(
|
|
1259
|
+
`I found ${bomData.bomJson.components.length} mix packages.`,
|
|
1260
|
+
);
|
|
1261
|
+
if (DEBUG_MODE) {
|
|
1262
|
+
console.log(
|
|
1263
|
+
`Found ${bomData.bomJson.components.length} mix packages at ${path}`,
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
components = components.concat(bomData.bomJson.components);
|
|
1267
|
+
dependencies = mergeDependencies(
|
|
1268
|
+
dependencies,
|
|
1269
|
+
bomData.bomJson.dependencies,
|
|
1270
|
+
);
|
|
1271
|
+
if (
|
|
1272
|
+
bomData.parentComponent &&
|
|
1273
|
+
Object.keys(bomData.parentComponent).length
|
|
1274
|
+
) {
|
|
1275
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
if (hasAnyProjectType(["oci", "c"], options)) {
|
|
1280
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1281
|
+
thoughtLog(
|
|
1282
|
+
"**C/C++**: Looking for C/C++ projects. Should I warn the user that the generated SBOM might have low accuracy and contain errors?",
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
setProjectTypeActivityContext("c", path);
|
|
1286
|
+
bomData = createCppBom(path, options);
|
|
1287
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1288
|
+
thoughtLog(
|
|
1289
|
+
`I found ${bomData.bomJson.components.length} cpp packages.`,
|
|
1290
|
+
);
|
|
1291
|
+
if (DEBUG_MODE) {
|
|
1292
|
+
console.log(
|
|
1293
|
+
`Found ${bomData.bomJson.components.length} cpp packages at ${path}`,
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
components = components.concat(bomData.bomJson.components);
|
|
1297
|
+
dependencies = mergeDependencies(
|
|
1298
|
+
dependencies,
|
|
1299
|
+
bomData.bomJson.dependencies,
|
|
1300
|
+
);
|
|
1301
|
+
if (
|
|
1302
|
+
bomData.parentComponent &&
|
|
1303
|
+
Object.keys(bomData.parentComponent).length
|
|
1304
|
+
) {
|
|
1305
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
if (hasAnyProjectType(["oci", "clojure"], options)) {
|
|
1310
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1311
|
+
thoughtLog(
|
|
1312
|
+
"**CLOJURE**: Looking for Clojure projects. Should I warn the user that the purl namespace 'clojars' isn't widely supported by tools like Dependency-Track?",
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
setProjectTypeActivityContext("clojure", path);
|
|
1316
|
+
bomData = createClojureBom(path, options);
|
|
1317
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1318
|
+
thoughtLog(
|
|
1319
|
+
`I found ${bomData.bomJson.components.length} clojure packages.`,
|
|
1320
|
+
);
|
|
1321
|
+
if (DEBUG_MODE) {
|
|
1322
|
+
console.log(
|
|
1323
|
+
`Found ${bomData.bomJson.components.length} clojure packages at ${path}`,
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
components = components.concat(bomData.bomJson.components);
|
|
1327
|
+
dependencies = mergeDependencies(
|
|
1328
|
+
dependencies,
|
|
1329
|
+
bomData.bomJson.dependencies,
|
|
1330
|
+
);
|
|
1331
|
+
if (
|
|
1332
|
+
bomData.parentComponent &&
|
|
1333
|
+
Object.keys(bomData.parentComponent).length
|
|
1334
|
+
) {
|
|
1335
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
if (hasAnyProjectType(["oci", "github"], options)) {
|
|
1340
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1341
|
+
thoughtLog(
|
|
1342
|
+
"**GITHUB**: Looking for any github packages and workflows.",
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
setProjectTypeActivityContext("github", path);
|
|
1346
|
+
bomData = createGitHubBom(path, options);
|
|
1347
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1348
|
+
thoughtLog(
|
|
1349
|
+
`I found ${bomData.bomJson.components.length} github action packages as well. Should I convert these to formulation instead 🤔`,
|
|
1350
|
+
);
|
|
1351
|
+
if (DEBUG_MODE) {
|
|
1352
|
+
console.log(
|
|
1353
|
+
`Found ${bomData.bomJson.components.length} GitHub action packages at ${path}`,
|
|
1354
|
+
);
|
|
1355
|
+
}
|
|
1356
|
+
components = components.concat(bomData.bomJson.components);
|
|
1357
|
+
dependencies = mergeDependencies(
|
|
1358
|
+
dependencies,
|
|
1359
|
+
bomData.bomJson.dependencies,
|
|
1360
|
+
);
|
|
1361
|
+
if (
|
|
1362
|
+
bomData.parentComponent &&
|
|
1363
|
+
Object.keys(bomData.parentComponent).length
|
|
1364
|
+
) {
|
|
1365
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
if (hasAnyProjectType(["oci", "cloudbuild"], options)) {
|
|
1370
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1371
|
+
thoughtLog(
|
|
1372
|
+
"**CLOUDBUILD**: Let's check for CloudBuild configuration files that include package dependencies.",
|
|
1373
|
+
);
|
|
1374
|
+
}
|
|
1375
|
+
setProjectTypeActivityContext("cloudbuild", path);
|
|
1376
|
+
bomData = createCloudBuildBom(path, options);
|
|
1377
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1378
|
+
thoughtLog(
|
|
1379
|
+
`I found ${bomData.bomJson.components.length} cloudbuild packages.`,
|
|
1380
|
+
);
|
|
1381
|
+
if (DEBUG_MODE) {
|
|
1382
|
+
console.log(
|
|
1383
|
+
`Found ${bomData.bomJson.components.length} CloudBuild configuration at ${path}`,
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
components = components.concat(bomData.bomJson.components);
|
|
1387
|
+
dependencies = mergeDependencies(
|
|
1388
|
+
dependencies,
|
|
1389
|
+
bomData.bomJson.dependencies,
|
|
1390
|
+
);
|
|
1391
|
+
if (
|
|
1392
|
+
bomData.parentComponent &&
|
|
1393
|
+
Object.keys(bomData.parentComponent).length
|
|
1394
|
+
) {
|
|
1395
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
if (hasAnyProjectType(["oci", "swift"], options)) {
|
|
1400
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1401
|
+
thoughtLog(
|
|
1402
|
+
"**SWIFT**: Now checking for Swift projects. We don't support CocoaPods, Objective-C, or pure Xcode projects, so the SBOM will be incomplete.",
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
setProjectTypeActivityContext("swift", path);
|
|
1406
|
+
bomData = await createSwiftBom(path, options);
|
|
1407
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1408
|
+
thoughtLog(
|
|
1409
|
+
`I found ${bomData.bomJson.components.length} swift packages here.`,
|
|
1410
|
+
);
|
|
1411
|
+
if (DEBUG_MODE) {
|
|
1412
|
+
console.log(
|
|
1413
|
+
`Found ${bomData.bomJson.components.length} Swift packages at ${path}`,
|
|
1414
|
+
);
|
|
1415
|
+
}
|
|
1416
|
+
components = components.concat(bomData.bomJson.components);
|
|
1417
|
+
dependencies = mergeDependencies(
|
|
1418
|
+
dependencies,
|
|
1419
|
+
bomData.bomJson.dependencies,
|
|
1420
|
+
);
|
|
1421
|
+
if (
|
|
1422
|
+
bomData.parentComponent &&
|
|
1423
|
+
Object.keys(bomData.parentComponent).length
|
|
1424
|
+
) {
|
|
1425
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
if (hasAnyProjectType(["oci", "jar", "war", "ear"], options)) {
|
|
1430
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1431
|
+
thoughtLog(
|
|
1432
|
+
"**JAR**: Let's check for any bundled jar/war/ear files to improve the SBOM accuracy.",
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
setProjectTypeActivityContext("jar", path);
|
|
1436
|
+
bomData = await createJarBom(path, options);
|
|
1437
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1438
|
+
thoughtLog(
|
|
1439
|
+
`I found ${bomData.bomJson.components.length} jar packages as well.`,
|
|
1440
|
+
);
|
|
1441
|
+
if (DEBUG_MODE) {
|
|
1442
|
+
console.log(
|
|
1443
|
+
`Found ${bomData.bomJson.components.length} jar packages at ${path}`,
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
components = components.concat(bomData.bomJson.components);
|
|
1447
|
+
dependencies = mergeDependencies(
|
|
1448
|
+
dependencies,
|
|
1449
|
+
bomData.bomJson.dependencies,
|
|
1450
|
+
);
|
|
1451
|
+
if (
|
|
1452
|
+
bomData.parentComponent &&
|
|
1453
|
+
Object.keys(bomData.parentComponent).length
|
|
1454
|
+
) {
|
|
1455
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
if (hasAnyProjectType(["oci", "cocoa"], options)) {
|
|
1460
|
+
setProjectTypeActivityContext("cocoa", path);
|
|
1461
|
+
bomData = await createCocoaBom(path, options);
|
|
1462
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1463
|
+
if (DEBUG_MODE) {
|
|
1464
|
+
console.log(
|
|
1465
|
+
`Found ${bomData.bomJson.components.length} Cocoa packages at ${path}`,
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
components = components.concat(bomData.bomJson.components);
|
|
1469
|
+
dependencies = dependencies.concat(bomData.bomJson.dependencies);
|
|
1470
|
+
if (
|
|
1471
|
+
bomData.parentComponent &&
|
|
1472
|
+
Object.keys(bomData.parentComponent).length
|
|
1473
|
+
) {
|
|
1474
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
if (hasAnyProjectType(["oci", "nix"], options)) {
|
|
1479
|
+
setProjectTypeActivityContext("nix", path);
|
|
1480
|
+
bomData = await createNixBom(path, options);
|
|
1481
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1482
|
+
if (DEBUG_MODE) {
|
|
1483
|
+
console.log(
|
|
1484
|
+
`Found ${bomData.bomJson.components.length} Nix flake packages at ${path}`,
|
|
1485
|
+
);
|
|
1486
|
+
}
|
|
1487
|
+
components = components.concat(bomData.bomJson.components);
|
|
1488
|
+
dependencies = mergeDependencies(
|
|
1489
|
+
dependencies,
|
|
1490
|
+
bomData.bomJson.dependencies,
|
|
1491
|
+
);
|
|
1492
|
+
if (
|
|
1493
|
+
bomData.parentComponent &&
|
|
1494
|
+
Object.keys(bomData.parentComponent).length
|
|
1495
|
+
) {
|
|
1496
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
if (hasAnyProjectType(["caxa"], options, false)) {
|
|
1501
|
+
setProjectTypeActivityContext("caxa", path);
|
|
1502
|
+
bomData = await createCaxaBom(path, options);
|
|
1503
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1504
|
+
if (DEBUG_MODE) {
|
|
1505
|
+
console.log(
|
|
1506
|
+
`Found ${bomData.bomJson.components.length} caxa packages at ${path}`,
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
1509
|
+
components = components.concat(bomData.bomJson.components);
|
|
1510
|
+
dependencies = mergeDependencies(
|
|
1511
|
+
dependencies,
|
|
1512
|
+
bomData.bomJson.dependencies,
|
|
1513
|
+
);
|
|
1514
|
+
if (
|
|
1515
|
+
bomData.parentComponent &&
|
|
1516
|
+
Object.keys(bomData.parentComponent).length
|
|
1517
|
+
) {
|
|
1518
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
if (hasAnyProjectType(["asar"], options, false)) {
|
|
1523
|
+
setProjectTypeActivityContext("asar", path);
|
|
1524
|
+
bomData = await createAsarBom(path, options);
|
|
1525
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1526
|
+
if (DEBUG_MODE) {
|
|
1527
|
+
console.log(
|
|
1528
|
+
`Found ${bomData.bomJson.components.length} ASAR component(s) at ${path}`,
|
|
1529
|
+
);
|
|
1530
|
+
}
|
|
1531
|
+
components = components.concat(bomData.bomJson.components);
|
|
1532
|
+
dependencies = mergeDependencies(
|
|
1533
|
+
dependencies,
|
|
1534
|
+
bomData.bomJson.dependencies,
|
|
1535
|
+
);
|
|
1536
|
+
if (
|
|
1537
|
+
bomData.parentComponent &&
|
|
1538
|
+
Object.keys(bomData.parentComponent).length
|
|
1539
|
+
) {
|
|
1540
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
if (hasAnyProjectType(["vscode-extension"], options, false)) {
|
|
1545
|
+
setProjectTypeActivityContext("vscode-extension", path);
|
|
1546
|
+
bomData = await createVscodeExtensionBom(path, options);
|
|
1547
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1548
|
+
if (DEBUG_MODE) {
|
|
1549
|
+
console.log(
|
|
1550
|
+
`Found ${bomData.bomJson.components.length} VS Code extension(s) at ${path}`,
|
|
1551
|
+
);
|
|
1552
|
+
}
|
|
1553
|
+
components = components.concat(bomData.bomJson.components);
|
|
1554
|
+
dependencies = mergeDependencies(
|
|
1555
|
+
dependencies,
|
|
1556
|
+
bomData.bomJson.dependencies,
|
|
1557
|
+
);
|
|
1558
|
+
if (
|
|
1559
|
+
bomData.parentComponent &&
|
|
1560
|
+
Object.keys(bomData.parentComponent).length
|
|
1561
|
+
) {
|
|
1562
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
if (hasAnyProjectType(["chrome-extension"], options, false)) {
|
|
1567
|
+
let isExplicitChromeExtensionPath = false;
|
|
1568
|
+
if (safeExistsSync(path)) {
|
|
1569
|
+
if (basename(path) === "manifest.json") {
|
|
1570
|
+
isExplicitChromeExtensionPath = true;
|
|
1571
|
+
} else {
|
|
1572
|
+
try {
|
|
1573
|
+
isExplicitChromeExtensionPath =
|
|
1574
|
+
statSync(path).isDirectory() &&
|
|
1575
|
+
safeExistsSync(join(path, "manifest.json"));
|
|
1576
|
+
} catch (_err) {
|
|
1577
|
+
isExplicitChromeExtensionPath = false;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
if (
|
|
1582
|
+
isExplicitChromeExtensionPath ||
|
|
1583
|
+
!sharedOptions.__didScanChromeExtensions
|
|
1584
|
+
) {
|
|
1585
|
+
if (!isExplicitChromeExtensionPath) {
|
|
1586
|
+
sharedOptions.__didScanChromeExtensions = true;
|
|
1587
|
+
}
|
|
1588
|
+
setProjectTypeActivityContext("chrome-extension", path);
|
|
1589
|
+
bomData = await createChromeExtensionBom(path, options);
|
|
1590
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1591
|
+
if (DEBUG_MODE) {
|
|
1592
|
+
console.log(
|
|
1593
|
+
`Found ${bomData.bomJson.components.length} Chrome extension(s) on this host`,
|
|
1594
|
+
);
|
|
1595
|
+
}
|
|
1596
|
+
components = components.concat(bomData.bomJson.components);
|
|
1597
|
+
dependencies = mergeDependencies(
|
|
1598
|
+
dependencies,
|
|
1599
|
+
bomData.bomJson.dependencies,
|
|
1600
|
+
);
|
|
1601
|
+
if (
|
|
1602
|
+
bomData.parentComponent &&
|
|
1603
|
+
Object.keys(bomData.parentComponent).length
|
|
1604
|
+
) {
|
|
1605
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
// Collect any crypto keys
|
|
1611
|
+
if (
|
|
1612
|
+
options.specVersion >= 1.6 &&
|
|
1613
|
+
options.includeCrypto &&
|
|
1614
|
+
isCycloneDxComponentTypeEnabled("cryptographic-asset", options)
|
|
1615
|
+
) {
|
|
1616
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1617
|
+
thoughtLog(
|
|
1618
|
+
"**CBOM**: Wait, the user wants me to look for cryptographic assets. Let's check thoroughly.",
|
|
1619
|
+
);
|
|
1620
|
+
}
|
|
1621
|
+
setProjectTypeActivityContext("cbom", path);
|
|
1622
|
+
bomData = await createCryptoCertsBom(path, options);
|
|
1623
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1624
|
+
thoughtLog(
|
|
1625
|
+
`I found ${bomData.bomJson.components.length} crypto assets.`,
|
|
1626
|
+
);
|
|
1627
|
+
if (DEBUG_MODE) {
|
|
1628
|
+
console.log(
|
|
1629
|
+
`Found ${bomData.bomJson.components.length} crypto assets at ${path}`,
|
|
1630
|
+
);
|
|
1631
|
+
}
|
|
1632
|
+
components = components.concat(bomData.bomJson.components);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return { components, dependencies, options, parentSubComponents };
|
|
1636
|
+
};
|
|
1637
|
+
const pathResults = [];
|
|
1638
|
+
// A container scan walks hundreds of paths, so the phase carries a bar and
|
|
1639
|
+
// names the path in flight rather than sitting silent for minutes.
|
|
1640
|
+
const scanPhase = ui.phase(
|
|
1641
|
+
`Scanning ${pathList.length} ${pathList.length === 1 ? "path" : "paths"}`,
|
|
1642
|
+
);
|
|
1643
|
+
let scannedPaths = 0;
|
|
1644
|
+
let foundComponents = 0;
|
|
1645
|
+
// Layer paths live under a temp directory whose name carries no information.
|
|
1646
|
+
// Reporting them relative to the exploded root shows the path as it exists
|
|
1647
|
+
// inside the image.
|
|
1648
|
+
const explodedRoot = options.allLayersExplodedDir;
|
|
1649
|
+
const displayPath = (path) =>
|
|
1650
|
+
explodedRoot && path.startsWith(explodedRoot)
|
|
1651
|
+
? path.slice(explodedRoot.length) || "/"
|
|
1652
|
+
: path;
|
|
1653
|
+
const trackedScanOnePath = async (path) => {
|
|
1654
|
+
scanPhase.detail(displayPath(path));
|
|
1655
|
+
try {
|
|
1656
|
+
const result = await scanOnePath(path);
|
|
1657
|
+
// Paths that yielded nothing stay silent, so the scrollback above the
|
|
1658
|
+
// live region reads as a running list of what was actually found.
|
|
1659
|
+
if (result.components.length) {
|
|
1660
|
+
foundComponents += result.components.length;
|
|
1661
|
+
ui.print(
|
|
1662
|
+
` ${summarizePurlTypes(result.components)} in ${displayPath(path)}`,
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
return result;
|
|
1666
|
+
} finally {
|
|
1667
|
+
scannedPaths += 1;
|
|
1668
|
+
scanPhase.progress(scannedPaths, pathList.length);
|
|
1669
|
+
}
|
|
1670
|
+
};
|
|
1671
|
+
if (pathScanConcurrency(pathList) > 1) {
|
|
1672
|
+
pathResults.push(
|
|
1673
|
+
...(await mapWithConcurrency(
|
|
1674
|
+
pathList,
|
|
1675
|
+
trackedScanOnePath,
|
|
1676
|
+
pathScanConcurrency(pathList),
|
|
1677
|
+
)),
|
|
1678
|
+
);
|
|
1679
|
+
} else {
|
|
1680
|
+
for (const path of pathList) {
|
|
1681
|
+
pathResults.push(await trackedScanOnePath(path));
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
scanPhase.succeed(
|
|
1685
|
+
summarizeCounts([[foundComponents, "component", "components"]]),
|
|
1686
|
+
);
|
|
1687
|
+
setDirWalkCacheRoot(undefined);
|
|
1688
|
+
for (const pathResult of pathResults) {
|
|
1689
|
+
components = components.concat(pathResult.components);
|
|
1690
|
+
dependencies = mergeDependencies(
|
|
1691
|
+
dependencies,
|
|
1692
|
+
pathResult.dependencies,
|
|
1693
|
+
parentComponent,
|
|
1694
|
+
);
|
|
1695
|
+
parentSubComponents = parentSubComponents.concat(
|
|
1696
|
+
pathResult.parentSubComponents,
|
|
1697
|
+
);
|
|
1698
|
+
if (pathResult.options.services?.length) {
|
|
1699
|
+
sharedOptions.services = mergeServices(
|
|
1700
|
+
sharedOptions.services || [],
|
|
1701
|
+
pathResult.options.services,
|
|
1702
|
+
);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
if (
|
|
1706
|
+
options.lastWorkingDir &&
|
|
1707
|
+
options.lastWorkingDir !== "" &&
|
|
1708
|
+
options.lastWorkingDir !== "/" &&
|
|
1709
|
+
!options.lastWorkingDir.includes("/opt/") &&
|
|
1710
|
+
!options.lastWorkingDir.includes("/home/")
|
|
1711
|
+
) {
|
|
1712
|
+
setProjectTypeActivityContext("jar", options.lastWorkingDir);
|
|
1713
|
+
bomData = createJarBom(options.lastWorkingDir, options);
|
|
1714
|
+
if (bomData?.bomJson?.components?.length) {
|
|
1715
|
+
if (DEBUG_MODE) {
|
|
1716
|
+
console.log(
|
|
1717
|
+
`Found ${bomData.bomJson.components.length} jar packages at ${options.lastWorkingDir}`,
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
components = components.concat(bomData.bomJson.components);
|
|
1721
|
+
dependencies = mergeDependencies(
|
|
1722
|
+
dependencies,
|
|
1723
|
+
bomData.bomJson.dependencies,
|
|
1724
|
+
);
|
|
1725
|
+
if (
|
|
1726
|
+
bomData.parentComponent &&
|
|
1727
|
+
Object.keys(bomData.parentComponent).length
|
|
1728
|
+
) {
|
|
1729
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
// Retain the components of parent component
|
|
1734
|
+
if (parentSubComponents.length) {
|
|
1735
|
+
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
1736
|
+
thoughtLog("**METADATA**: Tweaking the parent component hierarchy.");
|
|
1737
|
+
}
|
|
1738
|
+
if (!parentComponent || !Object.keys(parentComponent).length) {
|
|
1739
|
+
parentComponent = parentSubComponents[0];
|
|
1740
|
+
}
|
|
1741
|
+
// Our naive approach to appending to sub-components could result in same parent being included as a child
|
|
1742
|
+
// This is filtered out here
|
|
1743
|
+
parentSubComponents = parentSubComponents.filter(
|
|
1744
|
+
(c) => c["bom-ref"] !== parentComponent["bom-ref"],
|
|
1745
|
+
);
|
|
1746
|
+
parentComponent.components = trimComponents(parentSubComponents);
|
|
1747
|
+
if (
|
|
1748
|
+
parentComponent.components.length === 1 &&
|
|
1749
|
+
parentComponent.components[0].name === parentComponent.name &&
|
|
1750
|
+
!parentComponent.purl.startsWith("pkg:container")
|
|
1751
|
+
) {
|
|
1752
|
+
parentComponent = parentComponent.components[0];
|
|
1753
|
+
delete parentComponent.components;
|
|
1754
|
+
}
|
|
1755
|
+
// Add references between the multiple sub-boms
|
|
1756
|
+
let parentDependencies = dependencies.find(
|
|
1757
|
+
(d) => d["ref"] === parentComponent["bom-ref"],
|
|
1758
|
+
);
|
|
1759
|
+
if (!parentDependencies) {
|
|
1760
|
+
parentDependencies = {
|
|
1761
|
+
ref: parentComponent["bom-ref"],
|
|
1762
|
+
};
|
|
1763
|
+
dependencies = mergeDependencies(dependencies, parentDependencies);
|
|
1764
|
+
}
|
|
1765
|
+
if (!parentDependencies["dependsOn"]) {
|
|
1766
|
+
parentDependencies["dependsOn"] = [];
|
|
1767
|
+
}
|
|
1768
|
+
for (const parentSub of parentSubComponents) {
|
|
1769
|
+
// Issue: 1622. We might have already captured this parent component dependency
|
|
1770
|
+
if (!parentDependencies["dependsOn"].includes(parentSub["bom-ref"])) {
|
|
1771
|
+
parentDependencies["dependsOn"].push(parentSub["bom-ref"]);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
// some cleanup, but not complete
|
|
1776
|
+
for (const path of pathList) {
|
|
1777
|
+
if (path.startsWith(join(getTmpDir(), "docker-images-"))) {
|
|
1778
|
+
safeRmSync(path, { recursive: true, force: true });
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
const multiResult = dedupeBom(
|
|
1782
|
+
options,
|
|
1783
|
+
components,
|
|
1784
|
+
parentComponent,
|
|
1785
|
+
dependencies,
|
|
1786
|
+
);
|
|
1787
|
+
if (formulationList.length) {
|
|
1788
|
+
multiResult.formulationList = formulationList;
|
|
1789
|
+
}
|
|
1790
|
+
return multiResult;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
/**
|
|
1794
|
+
* Function to create a dynamic SBOM by executing a command and tracing the
|
|
1795
|
+
* shared libraries it loads at runtime via instrumentation.
|
|
1796
|
+
*
|
|
1797
|
+
* Components receive scope=required, evidence.identity[].methods[].technique=
|
|
1798
|
+
* instrumentation, and confidence 0.8 (version known) or 0.5 (version unknown).
|
|
1799
|
+
*
|
|
1800
|
+
* @param {string} path - Target path (used as working directory fallback)
|
|
1801
|
+
* @param {Object} options - CLI options; must include options.traceCmd
|
|
1802
|
+
* @returns {Promise<Object>} Promise resolving to BOM data object
|
|
1803
|
+
*/
|
|
1804
|
+
export async function createDynamicBom(path, options) {
|
|
1805
|
+
const commandStr = options.traceCmd;
|
|
1806
|
+
const workingDir = options.traceWorkingDir || path || process.cwd();
|
|
1807
|
+
|
|
1808
|
+
if (!commandStr) {
|
|
1809
|
+
console.error(
|
|
1810
|
+
"Missing required --trace-cmd option for dynamic project type.",
|
|
1811
|
+
);
|
|
1812
|
+
return buildBomNSData(options, [], "generic", {
|
|
1813
|
+
src: workingDir,
|
|
1814
|
+
projectType: "dynamic",
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
const traceOptions = {
|
|
1819
|
+
readPaths: options.traceReadPaths,
|
|
1820
|
+
writePaths: options.traceWritePaths,
|
|
1821
|
+
maxMemoryMB: options.traceMaxMemoryMB,
|
|
1822
|
+
maxCPUCores: options.traceMaxCPUCores,
|
|
1823
|
+
maxProcesses: options.traceMaxProcesses,
|
|
1824
|
+
timeoutMs: options.traceTimeoutMs,
|
|
1825
|
+
disableNetwork: options.traceDisableNetwork ?? true,
|
|
1826
|
+
traceHTTPURLs: options.traceHTTPURLs,
|
|
1827
|
+
tracePeriod: options.tracePeriod,
|
|
1828
|
+
allowEnvs: options.traceAllowEnvs,
|
|
1829
|
+
allowHidden: options.traceAllowHidden,
|
|
1830
|
+
allowListen: options.traceAllowListen,
|
|
1831
|
+
cryptoProbeMode: options.traceCryptoProbeMode,
|
|
1832
|
+
enableDiff: options.traceEnableDiff,
|
|
1833
|
+
strict: options.traceStrict,
|
|
1834
|
+
allowHosts: options.traceAllowHosts,
|
|
1835
|
+
allowPorts: options.traceAllowPorts,
|
|
1836
|
+
allowUrls: options.traceAllowUrls,
|
|
1837
|
+
blockFork: options.traceBlockFork,
|
|
1838
|
+
traceExec: options.traceTraceExec,
|
|
1839
|
+
allowExec: options.traceAllowExec,
|
|
1840
|
+
blockExec: options.traceBlockExec,
|
|
1841
|
+
traceCrypto: options.traceCrypto,
|
|
1842
|
+
cbom: options.cbom,
|
|
1843
|
+
};
|
|
1844
|
+
|
|
1845
|
+
const { components: pkgList, services: traceServices } =
|
|
1846
|
+
await buildDynamicComponents(commandStr, workingDir, traceOptions);
|
|
1847
|
+
|
|
1848
|
+
return buildBomNSData(options, pkgList, "generic", {
|
|
1849
|
+
src: workingDir,
|
|
1850
|
+
projectType: "dynamic",
|
|
1851
|
+
filename: commandStr,
|
|
1852
|
+
services: traceServices,
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
/**
|
|
1857
|
+
* Function to create bom string for various languages
|
|
1858
|
+
*
|
|
1859
|
+
* @param {string} path to the project
|
|
1860
|
+
* @param {Object} options Parse options from the cli
|
|
1861
|
+
* @returns {Promise<Object|undefined>} Promise resolving to BOM object, or undefined if path is not readable
|
|
1862
|
+
*/
|
|
1863
|
+
export async function createXBom(path, options) {
|
|
1864
|
+
try {
|
|
1865
|
+
accessSync(path, constants.R_OK);
|
|
1866
|
+
} catch (_err) {
|
|
1867
|
+
return undefined;
|
|
1868
|
+
}
|
|
1869
|
+
if (
|
|
1870
|
+
safeExistsSync(join(path, "package.json")) ||
|
|
1871
|
+
safeExistsSync(join(path, "rush.json")) ||
|
|
1872
|
+
safeExistsSync(join(path, "yarn.lock")) ||
|
|
1873
|
+
safeExistsSync(join(path, "bun.lock")) ||
|
|
1874
|
+
safeExistsSync(join(path, "bun.lockb")) ||
|
|
1875
|
+
safeExistsSync(join(path, "deno.lock")) ||
|
|
1876
|
+
safeExistsSync(join(path, "deno.json")) ||
|
|
1877
|
+
safeExistsSync(join(path, "deno.jsonc"))
|
|
1878
|
+
) {
|
|
1879
|
+
return await createNodejsBom(path, options);
|
|
1880
|
+
}
|
|
1881
|
+
// maven - pom.xml
|
|
1882
|
+
const pomFiles = getAllFiles(
|
|
1883
|
+
path,
|
|
1884
|
+
`${options.multiProject ? "**/" : ""}pom.xml`,
|
|
1885
|
+
options,
|
|
1886
|
+
);
|
|
1887
|
+
// gradle
|
|
1888
|
+
const gradleFiles = getAllFiles(
|
|
1889
|
+
path,
|
|
1890
|
+
`${options.multiProject ? "**/" : ""}build.gradle*`,
|
|
1891
|
+
options,
|
|
1892
|
+
);
|
|
1893
|
+
// scala sbt
|
|
1894
|
+
const sbtFiles = getAllFiles(
|
|
1895
|
+
path,
|
|
1896
|
+
`${options.multiProject ? "**/" : ""}{build.sbt,Build.scala}*`,
|
|
1897
|
+
options,
|
|
1898
|
+
);
|
|
1899
|
+
if (pomFiles.length || gradleFiles.length || sbtFiles.length) {
|
|
1900
|
+
return await createJavaBom(path, options);
|
|
1901
|
+
}
|
|
1902
|
+
// python
|
|
1903
|
+
const pipenvMode = safeExistsSync(join(path, "Pipfile"));
|
|
1904
|
+
const poetryMode = safeExistsSync(join(path, "poetry.lock"));
|
|
1905
|
+
const pyLockFiles = getAllFiles(
|
|
1906
|
+
path,
|
|
1907
|
+
`${options.multiProject ? "**/" : ""}pylock*.toml`,
|
|
1908
|
+
options,
|
|
1909
|
+
).filter((f) => isPyLockFile(f));
|
|
1910
|
+
const pyLockMode = pyLockFiles.length > 0;
|
|
1911
|
+
const pyProjectMode =
|
|
1912
|
+
!poetryMode && !pyLockMode && safeExistsSync(join(path, "pyproject.toml"));
|
|
1913
|
+
const setupPyMode = safeExistsSync(join(path, "setup.py"));
|
|
1914
|
+
if (pipenvMode || poetryMode || pyLockMode || pyProjectMode || setupPyMode) {
|
|
1915
|
+
return await createPythonBom(path, options);
|
|
1916
|
+
}
|
|
1917
|
+
const reqFiles = getAllFiles(
|
|
1918
|
+
path,
|
|
1919
|
+
`${options.multiProject ? "**/" : ""}*requirements*.txt`,
|
|
1920
|
+
options,
|
|
1921
|
+
);
|
|
1922
|
+
const reqDirFiles = getAllFiles(
|
|
1923
|
+
path,
|
|
1924
|
+
`${options.multiProject ? "**/" : ""}requirements/*.txt`,
|
|
1925
|
+
options,
|
|
1926
|
+
);
|
|
1927
|
+
const requirementsMode = reqFiles?.length || reqDirFiles?.length;
|
|
1928
|
+
const whlFiles = getAllFiles(
|
|
1929
|
+
path,
|
|
1930
|
+
`${options.multiProject ? "**/" : ""}*.whl`,
|
|
1931
|
+
options,
|
|
1932
|
+
);
|
|
1933
|
+
if (requirementsMode || whlFiles.length) {
|
|
1934
|
+
return await createPythonBom(path, options);
|
|
1935
|
+
}
|
|
1936
|
+
// go
|
|
1937
|
+
const gosumFiles = getAllFiles(
|
|
1938
|
+
path,
|
|
1939
|
+
`${options.multiProject ? "**/" : ""}go.sum`,
|
|
1940
|
+
options,
|
|
1941
|
+
);
|
|
1942
|
+
const gomodFiles = getAllFiles(
|
|
1943
|
+
path,
|
|
1944
|
+
`${options.multiProject ? "**/" : ""}go.mod`,
|
|
1945
|
+
options,
|
|
1946
|
+
);
|
|
1947
|
+
const gopkgLockFiles = getAllFiles(
|
|
1948
|
+
path,
|
|
1949
|
+
`${options.multiProject ? "**/" : ""}Gopkg.lock`,
|
|
1950
|
+
options,
|
|
1951
|
+
);
|
|
1952
|
+
if (gomodFiles.length || gosumFiles.length || gopkgLockFiles.length) {
|
|
1953
|
+
return await createGoBom(path, options);
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
// rust
|
|
1957
|
+
const cargoLockFiles = getAllFiles(
|
|
1958
|
+
path,
|
|
1959
|
+
`${options.multiProject ? "**/" : ""}Cargo.lock`,
|
|
1960
|
+
options,
|
|
1961
|
+
);
|
|
1962
|
+
const cargoFiles = getAllFiles(
|
|
1963
|
+
path,
|
|
1964
|
+
`${options.multiProject ? "**/" : ""}Cargo.toml`,
|
|
1965
|
+
options,
|
|
1966
|
+
);
|
|
1967
|
+
if (cargoLockFiles.length || cargoFiles.length) {
|
|
1968
|
+
return await createRustBom(path, options);
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
// php
|
|
1972
|
+
const composerJsonFiles = getAllFiles(
|
|
1973
|
+
path,
|
|
1974
|
+
`${options.multiProject ? "**/" : ""}composer.json`,
|
|
1975
|
+
options,
|
|
1976
|
+
);
|
|
1977
|
+
const composerLockFiles = getAllFiles(
|
|
1978
|
+
path,
|
|
1979
|
+
`${options.multiProject ? "**/" : ""}composer.lock`,
|
|
1980
|
+
options,
|
|
1981
|
+
);
|
|
1982
|
+
if (composerJsonFiles.length || composerLockFiles.length) {
|
|
1983
|
+
return createPHPBom(path, options);
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
// Ruby
|
|
1987
|
+
const gemFiles = getAllFiles(
|
|
1988
|
+
path,
|
|
1989
|
+
`${options.multiProject ? "**/" : ""}Gemfile`,
|
|
1990
|
+
options,
|
|
1991
|
+
);
|
|
1992
|
+
const gemLockFiles = getAllFiles(
|
|
1993
|
+
path,
|
|
1994
|
+
`${options.multiProject ? "**/" : ""}Gemfile*.lock`,
|
|
1995
|
+
options,
|
|
1996
|
+
);
|
|
1997
|
+
if (gemFiles.length || gemLockFiles.length) {
|
|
1998
|
+
return await createRubyBom(path, options);
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
// .Net
|
|
2002
|
+
const csProjFiles = getAllFiles(
|
|
2003
|
+
path,
|
|
2004
|
+
`${options.multiProject ? "**/" : ""}*.{cs,vb,fs,ts,hmi,plc}proj`,
|
|
2005
|
+
options,
|
|
2006
|
+
);
|
|
2007
|
+
if (csProjFiles.length) {
|
|
2008
|
+
return await createCsharpBom(path, options);
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
// Dart
|
|
2012
|
+
const pubFiles = getAllFiles(
|
|
2013
|
+
path,
|
|
2014
|
+
`${options.multiProject ? "**/" : ""}pubspec.lock`,
|
|
2015
|
+
options,
|
|
2016
|
+
);
|
|
2017
|
+
const pubSpecFiles = getAllFiles(
|
|
2018
|
+
path,
|
|
2019
|
+
`${options.multiProject ? "**/" : ""}pubspec.yaml`,
|
|
2020
|
+
options,
|
|
2021
|
+
);
|
|
2022
|
+
if (pubFiles.length || pubSpecFiles.length) {
|
|
2023
|
+
return await createDartBom(path, options);
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
// Haskell
|
|
2027
|
+
const hackageFiles = getAllFiles(
|
|
2028
|
+
path,
|
|
2029
|
+
`${options.multiProject ? "**/" : ""}cabal.project.freeze`,
|
|
2030
|
+
options,
|
|
2031
|
+
);
|
|
2032
|
+
if (hackageFiles.length) {
|
|
2033
|
+
return createHaskellBom(path, options);
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
// Elixir
|
|
2037
|
+
const mixFiles = getAllFiles(
|
|
2038
|
+
path,
|
|
2039
|
+
`${options.multiProject ? "**/" : ""}mix.lock`,
|
|
2040
|
+
options,
|
|
2041
|
+
);
|
|
2042
|
+
if (mixFiles.length) {
|
|
2043
|
+
return createElixirBom(path, options);
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
// cpp
|
|
2047
|
+
const conanLockFiles = getAllFiles(
|
|
2048
|
+
path,
|
|
2049
|
+
`${options.multiProject ? "**/" : ""}conan.lock`,
|
|
2050
|
+
options,
|
|
2051
|
+
);
|
|
2052
|
+
const colliderLockFiles = getAllFiles(
|
|
2053
|
+
path,
|
|
2054
|
+
`${options.multiProject ? "**/" : ""}collider.lock`,
|
|
2055
|
+
options,
|
|
2056
|
+
);
|
|
2057
|
+
const conanFiles = getAllFiles(
|
|
2058
|
+
path,
|
|
2059
|
+
`${options.multiProject ? "**/" : ""}conanfile.txt`,
|
|
2060
|
+
options,
|
|
2061
|
+
);
|
|
2062
|
+
const cmakeListFiles = getAllFiles(
|
|
2063
|
+
path,
|
|
2064
|
+
`${options.multiProject ? "**/" : ""}CMakeLists.txt`,
|
|
2065
|
+
options,
|
|
2066
|
+
);
|
|
2067
|
+
const mesonBuildFiles = getAllFiles(
|
|
2068
|
+
path,
|
|
2069
|
+
`${options.multiProject ? "**/" : ""}meson.build`,
|
|
2070
|
+
options,
|
|
2071
|
+
);
|
|
2072
|
+
if (
|
|
2073
|
+
colliderLockFiles.length ||
|
|
2074
|
+
conanLockFiles.length ||
|
|
2075
|
+
conanFiles.length ||
|
|
2076
|
+
cmakeListFiles.length ||
|
|
2077
|
+
mesonBuildFiles.length
|
|
2078
|
+
) {
|
|
2079
|
+
return createCppBom(path, options);
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
// clojure
|
|
2083
|
+
const ednFiles = getAllFiles(
|
|
2084
|
+
path,
|
|
2085
|
+
`${options.multiProject ? "**/" : ""}deps.edn`,
|
|
2086
|
+
options,
|
|
2087
|
+
);
|
|
2088
|
+
const leinFiles = getAllFiles(
|
|
2089
|
+
path,
|
|
2090
|
+
`${options.multiProject ? "**/" : ""}project.clj`,
|
|
2091
|
+
options,
|
|
2092
|
+
);
|
|
2093
|
+
if (ednFiles.length || leinFiles.length) {
|
|
2094
|
+
return createClojureBom(path, options);
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
// GitHub actions
|
|
2098
|
+
const ghactionFiles = getAllFiles(
|
|
2099
|
+
path,
|
|
2100
|
+
".github/workflows/" + "*.{yml,yaml}",
|
|
2101
|
+
options,
|
|
2102
|
+
);
|
|
2103
|
+
if (ghactionFiles.length) {
|
|
2104
|
+
return createGitHubBom(path, options);
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
// Jenkins plugins
|
|
2108
|
+
const hpiFiles = getAllFiles(
|
|
2109
|
+
path,
|
|
2110
|
+
`${options.multiProject ? "**/" : ""}*.hpi`,
|
|
2111
|
+
options,
|
|
2112
|
+
);
|
|
2113
|
+
if (hpiFiles.length) {
|
|
2114
|
+
return await createJenkinsBom(path, options);
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
// VS Code extensions (.vsix files)
|
|
2118
|
+
const vsixFiles = getAllFiles(
|
|
2119
|
+
path,
|
|
2120
|
+
`${options.multiProject ? "**/" : ""}*.vsix`,
|
|
2121
|
+
options,
|
|
2122
|
+
);
|
|
2123
|
+
if (vsixFiles.length) {
|
|
2124
|
+
return await createVscodeExtensionBom(path, options);
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
// Electron ASAR archives
|
|
2128
|
+
const asarFiles = getAllFiles(
|
|
2129
|
+
path,
|
|
2130
|
+
`${options.multiProject ? "**/" : ""}*.asar`,
|
|
2131
|
+
options,
|
|
2132
|
+
);
|
|
2133
|
+
if (asarFiles.length) {
|
|
2134
|
+
return await createAsarBom(path, options);
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
// Helm charts
|
|
2138
|
+
const chartFiles = getAllFiles(
|
|
2139
|
+
path,
|
|
2140
|
+
`${options.multiProject ? "**/" : ""}Chart.yaml`,
|
|
2141
|
+
options,
|
|
2142
|
+
);
|
|
2143
|
+
const yamlFiles = getAllFiles(
|
|
2144
|
+
path,
|
|
2145
|
+
`${options.multiProject ? "**/" : ""}values.yaml`,
|
|
2146
|
+
options,
|
|
2147
|
+
);
|
|
2148
|
+
if (chartFiles.length || yamlFiles.length) {
|
|
2149
|
+
return createHelmBom(path, options);
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
// Docker compose, dockerfile, containerfile, kubernetes and skaffold
|
|
2153
|
+
const dcFiles = getAllFiles(
|
|
2154
|
+
path,
|
|
2155
|
+
`${options.multiProject ? "**/" : ""}docker-compose*.yml`,
|
|
2156
|
+
options,
|
|
2157
|
+
);
|
|
2158
|
+
const dfFiles = getAllFiles(
|
|
2159
|
+
path,
|
|
2160
|
+
`${options.multiProject ? "**/" : ""}*Dockerfile*`,
|
|
2161
|
+
options,
|
|
2162
|
+
);
|
|
2163
|
+
const cfFiles = getAllFiles(
|
|
2164
|
+
path,
|
|
2165
|
+
`${options.multiProject ? "**/" : ""}*Containerfile*`,
|
|
2166
|
+
options,
|
|
2167
|
+
);
|
|
2168
|
+
const skFiles = getAllFiles(
|
|
2169
|
+
path,
|
|
2170
|
+
`${options.multiProject ? "**/" : ""}skaffold.yaml`,
|
|
2171
|
+
options,
|
|
2172
|
+
);
|
|
2173
|
+
const deplFiles = getAllFiles(
|
|
2174
|
+
path,
|
|
2175
|
+
`${options.multiProject ? "**/" : ""}deployment.yaml`,
|
|
2176
|
+
options,
|
|
2177
|
+
);
|
|
2178
|
+
if (
|
|
2179
|
+
dcFiles.length ||
|
|
2180
|
+
dfFiles.length ||
|
|
2181
|
+
cfFiles.length ||
|
|
2182
|
+
skFiles.length ||
|
|
2183
|
+
deplFiles.length
|
|
2184
|
+
) {
|
|
2185
|
+
return await createContainerSpecLikeBom(path, options);
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
// Google CloudBuild
|
|
2189
|
+
const cbFiles = getAllFiles(
|
|
2190
|
+
path,
|
|
2191
|
+
`${options.multiProject ? "**/" : ""}cloudbuild.yaml`,
|
|
2192
|
+
options,
|
|
2193
|
+
);
|
|
2194
|
+
if (cbFiles.length) {
|
|
2195
|
+
return createCloudBuildBom(path, options);
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
// Swift
|
|
2199
|
+
const swiftFiles = getAllFiles(
|
|
2200
|
+
path,
|
|
2201
|
+
`${options.multiProject ? "**/" : ""}Package*.swift`,
|
|
2202
|
+
options,
|
|
2203
|
+
);
|
|
2204
|
+
const pkgResolvedFiles = getAllFiles(
|
|
2205
|
+
path,
|
|
2206
|
+
`${options.multiProject ? "**/" : ""}Package.resolved`,
|
|
2207
|
+
options,
|
|
2208
|
+
);
|
|
2209
|
+
if (swiftFiles.length || pkgResolvedFiles.length) {
|
|
2210
|
+
return await createSwiftBom(path, options);
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
// Cocoa
|
|
2214
|
+
const cocoaFiles = getAllFiles(
|
|
2215
|
+
path,
|
|
2216
|
+
`${options.multiProject ? "**/" : ""}Podfile`,
|
|
2217
|
+
options,
|
|
2218
|
+
);
|
|
2219
|
+
if (cocoaFiles.length) {
|
|
2220
|
+
return await createCocoaBom(path, options);
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
// Nix flakes
|
|
2224
|
+
const flakeNixFiles = getAllFiles(
|
|
2225
|
+
path,
|
|
2226
|
+
`${options.multiProject ? "**/" : ""}flake.nix`,
|
|
2227
|
+
options,
|
|
2228
|
+
);
|
|
2229
|
+
const flakeLockFiles = getAllFiles(
|
|
2230
|
+
path,
|
|
2231
|
+
`${options.multiProject ? "**/" : ""}flake.lock`,
|
|
2232
|
+
options,
|
|
2233
|
+
);
|
|
2234
|
+
if (flakeNixFiles.length || flakeLockFiles.length) {
|
|
2235
|
+
return await createNixBom(path, options);
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
// Zig
|
|
2239
|
+
const zigZonFiles = getAllFiles(
|
|
2240
|
+
path,
|
|
2241
|
+
`${options.multiProject ? "**/" : ""}build.zig.zon`,
|
|
2242
|
+
options,
|
|
2243
|
+
);
|
|
2244
|
+
if (zigZonFiles.length) {
|
|
2245
|
+
return await createZigBom(path, options);
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
// Gleam
|
|
2249
|
+
const gleamTomlFiles = getAllFiles(
|
|
2250
|
+
path,
|
|
2251
|
+
`${options.multiProject ? "**/" : ""}gleam.toml`,
|
|
2252
|
+
options,
|
|
2253
|
+
);
|
|
2254
|
+
if (gleamTomlFiles.length) {
|
|
2255
|
+
return await createGleamBom(path, options);
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
/**
|
|
2260
|
+
* Function to create a hardware BOM for the current host.
|
|
2261
|
+
*
|
|
2262
|
+
* @param {string} _path Source path (unused for live host HBOM generation)
|
|
2263
|
+
* @param {Object} options Parse options from the cli
|
|
2264
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
2265
|
+
*/
|
|
2266
|
+
export async function createHBom(_path, options) {
|
|
2267
|
+
ensureHbomRuntimeSupport(options, options.commandName || "hbom");
|
|
2268
|
+
let bomJson = await createHbomDocument(options);
|
|
2269
|
+
if (options.includeRuntime) {
|
|
2270
|
+
const runtimeOptions = {
|
|
2271
|
+
...options,
|
|
2272
|
+
includeRuntime: false,
|
|
2273
|
+
multiProject: false,
|
|
2274
|
+
projectType: ["os"],
|
|
2275
|
+
};
|
|
2276
|
+
const obomData = await createOSBom(_path, runtimeOptions);
|
|
2277
|
+
bomJson = mergeHostInventoryBoms(bomJson, obomData);
|
|
2278
|
+
} else {
|
|
2279
|
+
bomJson = mergeHostInventoryBoms(bomJson);
|
|
2280
|
+
}
|
|
2281
|
+
return {
|
|
2282
|
+
bomJson,
|
|
2283
|
+
dependencies: bomJson.dependencies || [],
|
|
2284
|
+
parentComponent: bomJson.metadata?.component,
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
/**
|
|
2289
|
+
* Function to create bom string for various languages
|
|
2290
|
+
*
|
|
2291
|
+
* @param {string} path to the project
|
|
2292
|
+
* @param {Object} options Parse options from the cli
|
|
2293
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
2294
|
+
*/
|
|
2295
|
+
export async function createBom(path, options) {
|
|
2296
|
+
clearFileDiscoveryCache();
|
|
2297
|
+
let { projectType } = options;
|
|
2298
|
+
if (!projectType) {
|
|
2299
|
+
projectType = [];
|
|
2300
|
+
}
|
|
2301
|
+
ensureNoMixedHbomProjectTypes(projectType);
|
|
2302
|
+
if (hasHbomProjectType(projectType)) {
|
|
2303
|
+
const selectedHbomProjectType = Array.isArray(projectType)
|
|
2304
|
+
? projectType[0]
|
|
2305
|
+
: `${projectType}`.split(",")[0];
|
|
2306
|
+
options.projectType = [selectedHbomProjectType];
|
|
2307
|
+
setActivityContext({
|
|
2308
|
+
projectType: selectedHbomProjectType,
|
|
2309
|
+
sourcePath: path,
|
|
2310
|
+
});
|
|
2311
|
+
thoughtLog(
|
|
2312
|
+
"The user wants a Hardware Bill-of-Materials (HBOM) for the current host. Let's use the dedicated hardware collector.",
|
|
2313
|
+
);
|
|
2314
|
+
return await createHBom(path, options);
|
|
2315
|
+
}
|
|
2316
|
+
let exportData;
|
|
2317
|
+
let isContainerMode = false;
|
|
2318
|
+
const isLocalDirectoryInput =
|
|
2319
|
+
!options.projectType?.includes("universal") &&
|
|
2320
|
+
safeExistsSync(path) &&
|
|
2321
|
+
lstatSync(path).isDirectory();
|
|
2322
|
+
// Docker and image archive support
|
|
2323
|
+
// TODO: Support any source archive
|
|
2324
|
+
if (path.endsWith(".tar") || path.endsWith(".tar.gz")) {
|
|
2325
|
+
exportData = await exportArchive(path, options);
|
|
2326
|
+
if (!exportData) {
|
|
2327
|
+
console.log(
|
|
2328
|
+
`OS BOM generation has failed due to problems with exporting the image ${path}`,
|
|
2329
|
+
);
|
|
2330
|
+
options.failOnError && process.exit(1);
|
|
2331
|
+
return {};
|
|
2332
|
+
}
|
|
2333
|
+
isContainerMode = true;
|
|
2334
|
+
} else if (
|
|
2335
|
+
isLocalDirectoryInput &&
|
|
2336
|
+
(hasAnyProjectType(["oci-dir"], options, false) ||
|
|
2337
|
+
hasAnyProjectType(["oci"], options, false))
|
|
2338
|
+
) {
|
|
2339
|
+
isContainerMode = true;
|
|
2340
|
+
exportData = {
|
|
2341
|
+
inspectData: undefined,
|
|
2342
|
+
lastWorkingDir: "",
|
|
2343
|
+
allLayersDir: path,
|
|
2344
|
+
allLayersExplodedDir: path,
|
|
2345
|
+
};
|
|
2346
|
+
if (safeExistsSync(join(path, "all-layers"))) {
|
|
2347
|
+
exportData.allLayersExplodedDir = join(path, "all-layers");
|
|
2348
|
+
}
|
|
2349
|
+
exportData.pkgPathList = getPkgPathList(exportData, undefined);
|
|
2350
|
+
} else if (
|
|
2351
|
+
(options.projectType &&
|
|
2352
|
+
!options.projectType?.includes("universal") &&
|
|
2353
|
+
hasAnyProjectType(["oci"], options, false)) ||
|
|
2354
|
+
path.startsWith("docker.io") ||
|
|
2355
|
+
path.startsWith("quay.io") ||
|
|
2356
|
+
path.startsWith("ghcr.io") ||
|
|
2357
|
+
path.startsWith("mcr.microsoft.com") ||
|
|
2358
|
+
path.includes("@sha256") ||
|
|
2359
|
+
path.includes(":latest")
|
|
2360
|
+
) {
|
|
2361
|
+
exportData = await exportImage(path, options);
|
|
2362
|
+
if (exportData) {
|
|
2363
|
+
isContainerMode = true;
|
|
2364
|
+
} else {
|
|
2365
|
+
// Fail early for oci types
|
|
2366
|
+
if (hasAnyProjectType(["oci"], options, false)) {
|
|
2367
|
+
console.log(
|
|
2368
|
+
`OCI BOM generation has failed due to problems with exporting the image ${path}.`,
|
|
2369
|
+
);
|
|
2370
|
+
options.failOnError && process.exit(1);
|
|
2371
|
+
return {};
|
|
2372
|
+
}
|
|
2373
|
+
if (DEBUG_MODE) {
|
|
2374
|
+
console.log(path, "doesn't appear to be a valid container image.");
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
if (isContainerMode) {
|
|
2379
|
+
options.multiProject = true;
|
|
2380
|
+
options.installDeps = false;
|
|
2381
|
+
// Force the project type to oci
|
|
2382
|
+
options.projectType = ["oci"];
|
|
2383
|
+
// Pass the original path
|
|
2384
|
+
options.path = path;
|
|
2385
|
+
options.parentComponent = {};
|
|
2386
|
+
// Create parent component based on the inspect config
|
|
2387
|
+
const inspectData = exportData?.inspectData;
|
|
2388
|
+
if (
|
|
2389
|
+
inspectData?.RepoDigests &&
|
|
2390
|
+
inspectData.RepoTags &&
|
|
2391
|
+
Array.isArray(inspectData.RepoDigests) &&
|
|
2392
|
+
Array.isArray(inspectData.RepoTags) &&
|
|
2393
|
+
inspectData.RepoDigests.length &&
|
|
2394
|
+
inspectData.RepoTags.length
|
|
2395
|
+
) {
|
|
2396
|
+
const repoTag = inspectData.RepoTags[0];
|
|
2397
|
+
if (repoTag) {
|
|
2398
|
+
const tmpA = repoTag.split(":");
|
|
2399
|
+
if (tmpA && tmpA.length === 2) {
|
|
2400
|
+
options.parentComponent = {
|
|
2401
|
+
name: tmpA[0],
|
|
2402
|
+
version: tmpA[1],
|
|
2403
|
+
type: "container",
|
|
2404
|
+
_integrity: inspectData.RepoDigests[0].replace(
|
|
2405
|
+
"sha256:",
|
|
2406
|
+
"sha256-",
|
|
2407
|
+
),
|
|
2408
|
+
};
|
|
2409
|
+
applyPurl(
|
|
2410
|
+
options.parentComponent,
|
|
2411
|
+
ociPurl(inspectData.RepoDigests[0], tmpA[1]),
|
|
2412
|
+
);
|
|
2413
|
+
}
|
|
2414
|
+
} else if (inspectData.Id) {
|
|
2415
|
+
options.parentComponent = {
|
|
2416
|
+
name: inspectData.RepoDigests[0].split("@")[0],
|
|
2417
|
+
version: inspectData.RepoDigests[0]
|
|
2418
|
+
.split("@")[1]
|
|
2419
|
+
.replace("sha256:", ""),
|
|
2420
|
+
type: "container",
|
|
2421
|
+
_integrity: inspectData.RepoDigests[0].replace("sha256:", "sha256-"),
|
|
2422
|
+
};
|
|
2423
|
+
applyPurl(options.parentComponent, ociPurl(inspectData.RepoDigests[0]));
|
|
2424
|
+
}
|
|
2425
|
+
} else {
|
|
2426
|
+
options.parentComponent = createDefaultParentComponent(
|
|
2427
|
+
path,
|
|
2428
|
+
"container",
|
|
2429
|
+
options,
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
// Pass the entire export data about the image layers
|
|
2433
|
+
options.exportData = exportData;
|
|
2434
|
+
if (exportData?.binPaths) {
|
|
2435
|
+
options.binPaths = exportData.binPaths;
|
|
2436
|
+
}
|
|
2437
|
+
options.lastWorkingDir = exportData?.lastWorkingDir;
|
|
2438
|
+
options.allLayersExplodedDir = exportData?.allLayersExplodedDir;
|
|
2439
|
+
return await createMultiXBom(
|
|
2440
|
+
[...new Set(exportData?.pkgPathList)],
|
|
2441
|
+
options,
|
|
2442
|
+
);
|
|
2443
|
+
}
|
|
2444
|
+
if (path.endsWith(".war")) {
|
|
2445
|
+
projectType = ["java"];
|
|
2446
|
+
}
|
|
2447
|
+
if (!projectType.length && path.endsWith(".asar")) {
|
|
2448
|
+
projectType = ["asar"];
|
|
2449
|
+
}
|
|
2450
|
+
if (projectType.length > 1) {
|
|
2451
|
+
setActivityContext({
|
|
2452
|
+
projectType: projectType.join(","),
|
|
2453
|
+
sourcePath: path,
|
|
2454
|
+
});
|
|
2455
|
+
thoughtLog(
|
|
2456
|
+
`The user has specified multiple project types: ${projectType.join(", ")}. Let's focus on the types one at a time.`,
|
|
2457
|
+
);
|
|
2458
|
+
console.log("Generate BOM for project types:", projectType.join(", "));
|
|
2459
|
+
return await createMultiXBom(path, options);
|
|
2460
|
+
}
|
|
2461
|
+
if (projectType.length === 1) {
|
|
2462
|
+
setActivityContext({ projectType: projectType[0], sourcePath: path });
|
|
2463
|
+
if (hasAnyProjectType(["oci"], options, false)) {
|
|
2464
|
+
thoughtLog(
|
|
2465
|
+
"Okay, we're generating an SBOM for the OCI type. We'll need a compatible tool like Docker, Podman, or Nerdctl, along with the binary plugins.",
|
|
2466
|
+
);
|
|
2467
|
+
} else {
|
|
2468
|
+
thoughtLog(
|
|
2469
|
+
`The user wants me to focus on a single type, '${projectType}'.`,
|
|
2470
|
+
);
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
// Use the project type alias to return any singular BOM
|
|
2474
|
+
if (PROJECT_TYPE_ALIASES["java"].includes(projectType[0])) {
|
|
2475
|
+
return await createJavaBom(path, options);
|
|
2476
|
+
}
|
|
2477
|
+
if (PROJECT_TYPE_ALIASES["android"].includes(projectType[0])) {
|
|
2478
|
+
return createAndroidBom(path, options);
|
|
2479
|
+
}
|
|
2480
|
+
if (
|
|
2481
|
+
PROJECT_TYPE_ALIASES["js"].includes(projectType[0]) ||
|
|
2482
|
+
projectType?.[0]?.startsWith("node")
|
|
2483
|
+
) {
|
|
2484
|
+
return await createNodejsBom(path, options);
|
|
2485
|
+
}
|
|
2486
|
+
if (PROJECT_TYPE_ALIASES["mcp"].includes(projectType[0])) {
|
|
2487
|
+
return await createNodejsBom(path, options);
|
|
2488
|
+
}
|
|
2489
|
+
if (PROJECT_TYPE_ALIASES["ai-skill"].includes(projectType[0])) {
|
|
2490
|
+
return await createNodejsBom(path, options);
|
|
2491
|
+
}
|
|
2492
|
+
if (optionIncludesAiInventoryProjectType(projectType, "ai")) {
|
|
2493
|
+
return await createNodejsBom(path, options);
|
|
2494
|
+
}
|
|
2495
|
+
if (
|
|
2496
|
+
PROJECT_TYPE_ALIASES["py"].includes(projectType[0]) ||
|
|
2497
|
+
projectType?.[0]?.startsWith("python")
|
|
2498
|
+
) {
|
|
2499
|
+
return await createPythonBom(path, options);
|
|
2500
|
+
}
|
|
2501
|
+
if (PROJECT_TYPE_ALIASES["go"].includes(projectType[0])) {
|
|
2502
|
+
return await createGoBom(path, options);
|
|
2503
|
+
}
|
|
2504
|
+
if (PROJECT_TYPE_ALIASES["rust"].includes(projectType[0])) {
|
|
2505
|
+
return await createRustBom(path, options);
|
|
2506
|
+
}
|
|
2507
|
+
if (PROJECT_TYPE_ALIASES["cargo-cache"].includes(projectType[0])) {
|
|
2508
|
+
return await createCargoCacheBom(getCargoCacheDir(), options);
|
|
2509
|
+
}
|
|
2510
|
+
if (PROJECT_TYPE_ALIASES["php"].includes(projectType[0])) {
|
|
2511
|
+
return createPHPBom(path, options);
|
|
2512
|
+
}
|
|
2513
|
+
if (
|
|
2514
|
+
PROJECT_TYPE_ALIASES["ruby"].includes(projectType[0]) ||
|
|
2515
|
+
projectType?.[0]?.startsWith("ruby")
|
|
2516
|
+
) {
|
|
2517
|
+
return await createRubyBom(path, options);
|
|
2518
|
+
}
|
|
2519
|
+
if (PROJECT_TYPE_ALIASES["csharp"].includes(projectType[0])) {
|
|
2520
|
+
return await createCsharpBom(path, options);
|
|
2521
|
+
}
|
|
2522
|
+
if (PROJECT_TYPE_ALIASES["dart"].includes(projectType[0])) {
|
|
2523
|
+
return await createDartBom(path, options);
|
|
2524
|
+
}
|
|
2525
|
+
if (PROJECT_TYPE_ALIASES["haskell"].includes(projectType[0])) {
|
|
2526
|
+
return createHaskellBom(path, options);
|
|
2527
|
+
}
|
|
2528
|
+
if (PROJECT_TYPE_ALIASES["elixir"].includes(projectType[0])) {
|
|
2529
|
+
return createElixirBom(path, options);
|
|
2530
|
+
}
|
|
2531
|
+
if (PROJECT_TYPE_ALIASES["c"].includes(projectType[0])) {
|
|
2532
|
+
return createCppBom(path, options);
|
|
2533
|
+
}
|
|
2534
|
+
if (PROJECT_TYPE_ALIASES["clojure"].includes(projectType[0])) {
|
|
2535
|
+
return createClojureBom(path, options);
|
|
2536
|
+
}
|
|
2537
|
+
if (PROJECT_TYPE_ALIASES["github"].includes(projectType[0])) {
|
|
2538
|
+
return createGitHubBom(path, options);
|
|
2539
|
+
}
|
|
2540
|
+
if (PROJECT_TYPE_ALIASES["os"].includes(projectType[0])) {
|
|
2541
|
+
return await createOSBom(path, options);
|
|
2542
|
+
}
|
|
2543
|
+
if (PROJECT_TYPE_ALIASES["jenkins"].includes(projectType[0])) {
|
|
2544
|
+
return await createJenkinsBom(path, options);
|
|
2545
|
+
}
|
|
2546
|
+
if (PROJECT_TYPE_ALIASES["helm"].includes(projectType[0])) {
|
|
2547
|
+
return createHelmBom(path, options);
|
|
2548
|
+
}
|
|
2549
|
+
if (PROJECT_TYPE_ALIASES["helm-index"].includes(projectType[0])) {
|
|
2550
|
+
return createHelmBom(
|
|
2551
|
+
join(homedir(), ".cache", "helm", "repository"),
|
|
2552
|
+
options,
|
|
2553
|
+
);
|
|
2554
|
+
}
|
|
2555
|
+
if (PROJECT_TYPE_ALIASES["universal"].includes(projectType[0])) {
|
|
2556
|
+
return await createContainerSpecLikeBom(path, options);
|
|
2557
|
+
}
|
|
2558
|
+
if (PROJECT_TYPE_ALIASES["cloudbuild"].includes(projectType[0])) {
|
|
2559
|
+
return createCloudBuildBom(path, options);
|
|
2560
|
+
}
|
|
2561
|
+
if (PROJECT_TYPE_ALIASES["swift"].includes(projectType[0])) {
|
|
2562
|
+
return await createSwiftBom(path, options);
|
|
2563
|
+
}
|
|
2564
|
+
if (PROJECT_TYPE_ALIASES["binary"].includes(projectType[0])) {
|
|
2565
|
+
return createBinaryBom(path, options);
|
|
2566
|
+
}
|
|
2567
|
+
if (PROJECT_TYPE_ALIASES["cocoa"].includes(projectType[0])) {
|
|
2568
|
+
return await createCocoaBom(path, options);
|
|
2569
|
+
}
|
|
2570
|
+
if (PROJECT_TYPE_ALIASES["nix"].includes(projectType[0])) {
|
|
2571
|
+
return await createNixBom(path, options);
|
|
2572
|
+
}
|
|
2573
|
+
if (PROJECT_TYPE_ALIASES["zig"].includes(projectType[0])) {
|
|
2574
|
+
return await createZigBom(path, options);
|
|
2575
|
+
}
|
|
2576
|
+
if (PROJECT_TYPE_ALIASES["gleam"].includes(projectType[0])) {
|
|
2577
|
+
return await createGleamBom(path, options);
|
|
2578
|
+
}
|
|
2579
|
+
if (PROJECT_TYPE_ALIASES["caxa"].includes(projectType[0])) {
|
|
2580
|
+
return await createCaxaBom(path, options);
|
|
2581
|
+
}
|
|
2582
|
+
if (PROJECT_TYPE_ALIASES["asar"].includes(projectType[0])) {
|
|
2583
|
+
return await createAsarBom(path, options);
|
|
2584
|
+
}
|
|
2585
|
+
if (PROJECT_TYPE_ALIASES["vscode-extension"].includes(projectType[0])) {
|
|
2586
|
+
return await createVscodeExtensionBom(path, options);
|
|
2587
|
+
}
|
|
2588
|
+
if (PROJECT_TYPE_ALIASES["chrome-extension"].includes(projectType[0])) {
|
|
2589
|
+
return await createChromeExtensionBom(path, options);
|
|
2590
|
+
}
|
|
2591
|
+
if (PROJECT_TYPE_ALIASES["dynamic"].includes(projectType[0])) {
|
|
2592
|
+
return await createDynamicBom(path, options);
|
|
2593
|
+
}
|
|
2594
|
+
if (PROJECT_TYPE_ALIASES["ai-provenance"].includes(projectType[0])) {
|
|
2595
|
+
return buildBomNSData(options, [], "ai-provenance", { src: path });
|
|
2596
|
+
}
|
|
2597
|
+
switch (projectType[0]) {
|
|
2598
|
+
case "jar":
|
|
2599
|
+
return createJarBom(path, options);
|
|
2600
|
+
case "gradle-index":
|
|
2601
|
+
case "gradle-cache":
|
|
2602
|
+
options.useGradleCache = true;
|
|
2603
|
+
return createJarBom(GRADLE_CACHE_DIR, options);
|
|
2604
|
+
case "sbt-index":
|
|
2605
|
+
case "sbt-cache":
|
|
2606
|
+
options.useSbtCache = true;
|
|
2607
|
+
return createJarBom(SBT_CACHE_DIR, options);
|
|
2608
|
+
case "maven-index":
|
|
2609
|
+
case "maven-cache":
|
|
2610
|
+
case "maven-repo":
|
|
2611
|
+
options.useMavenCache = true;
|
|
2612
|
+
return createJarBom(
|
|
2613
|
+
readEnvironmentVariable("MAVEN_CACHE_DIR") ||
|
|
2614
|
+
join(homedir(), ".m2", "repository"),
|
|
2615
|
+
options,
|
|
2616
|
+
);
|
|
2617
|
+
default:
|
|
2618
|
+
// In recurse mode return multi-language Bom
|
|
2619
|
+
// https://github.com/cdxgen/cdxgen/issues/95
|
|
2620
|
+
if (options.multiProject) {
|
|
2621
|
+
return await createMultiXBom(path, options);
|
|
2622
|
+
}
|
|
2623
|
+
return await createXBom(path, options);
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
/**
|
|
2628
|
+
* Method to submit the generated bom to dependency-track or cyclonedx server
|
|
2629
|
+
*
|
|
2630
|
+
* @param {Object} args CLI args
|
|
2631
|
+
* @param {Object} bomContents BOM Json
|
|
2632
|
+
* @return {Promise<{ token: string } | undefined>} a promise with a token (if request was successful) or undefined (in case of invalid arguments)
|
|
2633
|
+
* @throws {Error} if the request fails
|
|
2634
|
+
*/
|
|
2635
|
+
export async function submitBom(args, bomContents) {
|
|
2636
|
+
const dependencyTrackApiUrl = getDependencyTrackBomApiUrl(args.serverUrl);
|
|
2637
|
+
const serverUrl = dependencyTrackApiUrl?.toString();
|
|
2638
|
+
if (!dependencyTrackApiUrl || !serverUrl) {
|
|
2639
|
+
console.log(
|
|
2640
|
+
"Invalid Dependency-Track server URL. Provide an absolute http(s) URL without dangerous characters.",
|
|
2641
|
+
);
|
|
2642
|
+
args.failOnError && process.exit(1);
|
|
2643
|
+
return undefined;
|
|
2644
|
+
}
|
|
2645
|
+
const serverHost = dependencyTrackApiUrl.hostname;
|
|
2646
|
+
if (!isAllowedHttpHost(serverHost)) {
|
|
2647
|
+
console.log(
|
|
2648
|
+
`Dependency-Track server host '${serverHost}' is not allowed by CDXGEN_ALLOWED_HOSTS.`,
|
|
2649
|
+
);
|
|
2650
|
+
args.failOnError && process.exit(1);
|
|
2651
|
+
return undefined;
|
|
2652
|
+
}
|
|
2653
|
+
if (isDryRun) {
|
|
2654
|
+
recordActivity({
|
|
2655
|
+
kind: "network",
|
|
2656
|
+
reason:
|
|
2657
|
+
"Dry run mode blocks Dependency-Track submission and reports the request instead.",
|
|
2658
|
+
status: "blocked",
|
|
2659
|
+
target: serverUrl,
|
|
2660
|
+
});
|
|
2661
|
+
return undefined;
|
|
2662
|
+
}
|
|
2663
|
+
const bomPayload = buildDependencyTrackBomPayload(args, bomContents);
|
|
2664
|
+
if (!bomPayload) {
|
|
2665
|
+
console.log(
|
|
2666
|
+
"Invalid Dependency-Track submission arguments. Provide projectId or projectName (projectVersion defaults to main) and specify parent project either by UUID or by parent project name + version.",
|
|
2667
|
+
);
|
|
2668
|
+
args.failOnError && process.exit(1);
|
|
2669
|
+
return;
|
|
2670
|
+
}
|
|
2671
|
+
if (DEBUG_MODE) {
|
|
2672
|
+
console.log(
|
|
2673
|
+
"Submitting BOM to",
|
|
2674
|
+
serverUrl,
|
|
2675
|
+
"params",
|
|
2676
|
+
args.projectName,
|
|
2677
|
+
bomPayload.projectVersion,
|
|
2678
|
+
);
|
|
2679
|
+
}
|
|
2680
|
+
try {
|
|
2681
|
+
const requestOptions = {
|
|
2682
|
+
method: "PUT",
|
|
2683
|
+
followRedirect: false,
|
|
2684
|
+
https: {
|
|
2685
|
+
rejectUnauthorized: !args.skipDtTlsCheck,
|
|
2686
|
+
},
|
|
2687
|
+
headers: {
|
|
2688
|
+
"X-Api-Key": (args.apiKey || "").replace(/[\r\n]/g, ""),
|
|
2689
|
+
"Content-Type": "application/json",
|
|
2690
|
+
},
|
|
2691
|
+
json: bomPayload,
|
|
2692
|
+
responseType: "json",
|
|
2693
|
+
context: {
|
|
2694
|
+
activityIntent: "bom-submit",
|
|
2695
|
+
},
|
|
2696
|
+
};
|
|
2697
|
+
if (DEBUG_MODE && args.skipDtTlsCheck) {
|
|
2698
|
+
console.log(
|
|
2699
|
+
"Calling ",
|
|
2700
|
+
serverUrl,
|
|
2701
|
+
"with --skip-dt-tls-check argument: Skip DT TLS check.",
|
|
2702
|
+
);
|
|
2703
|
+
}
|
|
2704
|
+
// See issue #1963 regarding CRLF hardening
|
|
2705
|
+
return await cdxgenAgent(dependencyTrackApiUrl, requestOptions).json();
|
|
2706
|
+
} catch (error) {
|
|
2707
|
+
if (error.response && error.response.statusCode === 401) {
|
|
2708
|
+
// Unauthorized
|
|
2709
|
+
console.log(
|
|
2710
|
+
"Received Unauthorized error. Check the API key used is valid and has necessary permissions to create projects and upload bom.",
|
|
2711
|
+
);
|
|
2712
|
+
} else if (error.response && error.response.statusCode === 405) {
|
|
2713
|
+
console.log(
|
|
2714
|
+
"Method PUT not allowed on Dependency-Track server. Trying with POST ...",
|
|
2715
|
+
);
|
|
2716
|
+
// Method not allowed errors
|
|
2717
|
+
try {
|
|
2718
|
+
return await cdxgenAgent(dependencyTrackApiUrl, {
|
|
2719
|
+
method: "POST",
|
|
2720
|
+
followRedirect: false,
|
|
2721
|
+
https: {
|
|
2722
|
+
rejectUnauthorized: !args.skipDtTlsCheck,
|
|
2723
|
+
},
|
|
2724
|
+
headers: {
|
|
2725
|
+
"X-Api-Key": (args.apiKey || "").replace(/[\r\n]/g, ""),
|
|
2726
|
+
"Content-Type": "application/json",
|
|
2727
|
+
},
|
|
2728
|
+
json: bomPayload,
|
|
2729
|
+
responseType: "json",
|
|
2730
|
+
context: {
|
|
2731
|
+
activityIntent: "bom-submit",
|
|
2732
|
+
},
|
|
2733
|
+
}).json();
|
|
2734
|
+
} catch (error) {
|
|
2735
|
+
if (DEBUG_MODE) {
|
|
2736
|
+
console.log(
|
|
2737
|
+
"Unable to submit the SBOM to the Dependency-Track server using POST method",
|
|
2738
|
+
error,
|
|
2739
|
+
);
|
|
2740
|
+
} else {
|
|
2741
|
+
console.log(
|
|
2742
|
+
"Unable to submit the SBOM to the Dependency-Track server using POST method",
|
|
2743
|
+
);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
} else {
|
|
2747
|
+
if (DEBUG_MODE) {
|
|
2748
|
+
console.log(
|
|
2749
|
+
"Unable to submit the SBOM to the Dependency-Track server using POST method",
|
|
2750
|
+
error,
|
|
2751
|
+
);
|
|
2752
|
+
} else {
|
|
2753
|
+
console.log("Unable to submit the SBOM to the Dependency-Track server");
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
// rethrow error as function is async and we should try to catch it in the caller
|
|
2757
|
+
throw error;
|
|
2758
|
+
}
|
|
2759
|
+
}
|