@cdxgen/cdxgen 0.0.1 → 13.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +921 -87
- package/bin/audit.js +239 -0
- package/bin/cdxgen.js +2335 -0
- package/bin/convert.js +220 -0
- package/bin/evinse.js +353 -0
- package/bin/hbom.js +504 -0
- package/bin/repl.js +2224 -0
- package/bin/sign.js +195 -0
- package/bin/tracebom.js +303 -0
- package/bin/validate.js +268 -0
- package/bin/verify.js +189 -0
- package/data/README.md +307 -0
- package/data/bom-1.4.schema.json +1605 -0
- package/data/bom-1.5.schema.json +3660 -0
- package/data/bom-1.6.schema.json +5511 -0
- package/data/bom-1.7.schema.json +6700 -0
- package/data/cbomosdb-queries.json +68 -0
- package/data/component-tags.json +339 -0
- package/data/container-knowledge-index.json +125 -0
- package/data/cosdb-queries.json +17 -0
- package/data/crypto-oid.json +1998 -0
- package/data/cryptography-defs.json +3793 -0
- package/data/cryptography-defs.schema.json +576 -0
- package/data/cyclonedx-2.0-bundled.schema.json +7182 -0
- package/data/frameworks-list.json +219 -0
- package/data/glibc-stdlib.json +117 -0
- package/data/gtfobins-index.json +6296 -0
- package/data/helpers/init.gradle +71 -0
- package/data/jsf-0.82.schema.json +211 -0
- package/data/known-licenses.json +82 -0
- package/data/lic-mapping.json +338 -0
- package/data/license-aliases.json +6624 -0
- package/data/license-db.json +39059 -0
- package/data/license-deprecations.json +302 -0
- package/data/lolbas-index.json +150 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/pypi-pkg-aliases.json +1199 -0
- package/data/python-stdlib.json +308 -0
- package/data/queries-darwin.json +193 -0
- package/data/queries-win.json +257 -0
- package/data/queries.json +268 -0
- package/data/ruby-known-modules.json +281 -0
- package/data/rules/ai-agent-governance.yaml +323 -0
- package/data/rules/ai-bom.yaml +268 -0
- package/data/rules/ai-oversight.yaml +186 -0
- package/data/rules/ai-provenance.yaml +92 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/cbom-security.yaml +165 -0
- package/data/rules/chrome-extensions.yaml +248 -0
- package/data/rules/ci-permissions.yaml +802 -0
- package/data/rules/container-risk.yaml +353 -0
- package/data/rules/dependency-sources.yaml +236 -0
- package/data/rules/golem-go.yaml +229 -0
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +388 -0
- package/data/rules/obom-runtime.yaml +1776 -0
- package/data/rules/package-integrity.yaml +364 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +237 -0
- package/data/spdx-export.schema.json +6794 -0
- package/data/spdx-license-list.json +7449 -0
- package/data/spdx-licenses.json +759 -0
- package/data/spdx.schema.json +819 -0
- package/data/templates/README.md +3 -0
- package/data/templates/asvs-4.0.3.cdx.json +2943 -0
- package/data/templates/asvs-5.0.cdx.json +3046 -0
- package/data/templates/bsimm-v13.cdx.json +1008 -0
- package/data/templates/masvs-2.0.0.cdx.json +225 -0
- package/data/templates/nist-ssdf-1.1.cdx.json +828 -0
- package/data/templates/pcissc-secure-slc-1.1.cdx.json +1027 -0
- package/data/templates/scvs-1.0.0.cdx.json +813 -0
- package/data/templates/ssaf-DRAFT-2023-11.cdx.json +127 -0
- package/data/vendor-alias.json +41967 -0
- package/data/wrapdb-releases.json +4227 -0
- package/index.cjs +15 -0
- package/lib/audit/index.js +2800 -0
- package/lib/audit/progress.js +114 -0
- package/lib/audit/reporters.js +937 -0
- package/lib/audit/scoring.js +560 -0
- package/lib/audit/targets.js +798 -0
- package/lib/cli/bomAssembly.js +1882 -0
- package/lib/cli/cliOptions.js +543 -0
- package/lib/cli/index.js +2759 -0
- package/lib/cli/jsBom.js +2087 -0
- package/lib/cli/jvmBom.js +1858 -0
- package/lib/cli/managedBom.js +2083 -0
- package/lib/cli/nativeBom.js +2125 -0
- package/lib/core/activity.js +1087 -0
- package/lib/core/env.js +719 -0
- package/lib/core/fs.js +1058 -0
- package/lib/core/httpClient.js +730 -0
- package/lib/core/logger.js +280 -0
- package/lib/core/parallel.js +323 -0
- package/lib/core/paths.js +70 -0
- package/lib/core/projectConfig.js +122 -0
- package/lib/core/propertySanitizer.js +174 -0
- package/lib/core/spdx.js +5 -0
- package/lib/core/state.js +59 -0
- package/lib/core/text.js +207 -0
- package/lib/core/ui.js +920 -0
- package/lib/core/urls.js +84 -0
- package/lib/ecosystems/asarutils.js +1636 -0
- package/lib/ecosystems/bunutils.js +402 -0
- package/lib/ecosystems/caxa.js +77 -0
- package/lib/ecosystems/chromextutils.js +1174 -0
- package/lib/ecosystems/cmakeResolver.js +587 -0
- package/lib/ecosystems/cppEvidence.js +305 -0
- package/lib/ecosystems/denoutils.js +1094 -0
- package/lib/ecosystems/dotnetutils.js +132 -0
- package/lib/ecosystems/ecosystems.js +2772 -0
- package/lib/ecosystems/golem.js +1807 -0
- package/lib/ecosystems/gradleutils.js +1048 -0
- package/lib/ecosystems/jsEvidence.js +317 -0
- package/lib/ecosystems/npmutils.js +586 -0
- package/lib/ecosystems/parsers-bazel.js +875 -0
- package/lib/ecosystems/parsers-dotnet.js +1430 -0
- package/lib/ecosystems/parsers-gleam.js +302 -0
- package/lib/ecosystems/parsers-go.js +818 -0
- package/lib/ecosystems/parsers-js.js +4222 -0
- package/lib/ecosystems/parsers-jvm.js +948 -0
- package/lib/ecosystems/parsers-misc.js +3191 -0
- package/lib/ecosystems/parsers-python.js +2070 -0
- package/lib/ecosystems/parsers-rust.js +1294 -0
- package/lib/ecosystems/parsers-zig.js +861 -0
- package/lib/ecosystems/pep770.js +341 -0
- package/lib/ecosystems/pylockutils.js +427 -0
- package/lib/ecosystems/pythonutils.js +1281 -0
- package/lib/ecosystems/registryProvenance.js +1003 -0
- package/lib/ecosystems/remote/huggingface.js +1343 -0
- package/lib/ecosystems/rubyutils.js +1629 -0
- package/lib/ecosystems/rusi.js +820 -0
- package/lib/ecosystems/sbtutils.js +972 -0
- package/lib/ecosystems/tea.js +607 -0
- package/lib/ecosystems/utils.js +583 -0
- package/lib/ecosystems/zigResolver.js +410 -0
- package/lib/evinser/db.js +145 -0
- package/lib/evinser/evinser.js +2362 -0
- package/lib/evinser/scalasem.js +65 -0
- package/lib/evinser/swiftsem.js +767 -0
- package/lib/helpers/annotationFormatter.js +84 -0
- package/lib/helpers/bomSigner.js +312 -0
- package/lib/helpers/exportUtils.js +160 -0
- package/lib/helpers/remote/dependency-track.js +117 -0
- package/lib/helpers/versutils.js +202 -0
- package/lib/helpers/vsixutils.js +1069 -0
- package/lib/inventory/agentFormulationParser.js +322 -0
- package/lib/inventory/aiCollector.js +2140 -0
- package/lib/inventory/aiInventory.js +414 -0
- package/lib/inventory/aiModelVariants.js +121 -0
- package/lib/inventory/aiOversightCollector.js +661 -0
- package/lib/inventory/aiProvenanceCollector.js +822 -0
- package/lib/inventory/analyzer.js +6089 -0
- package/lib/inventory/analyzerScope.js +807 -0
- package/lib/inventory/astWorker.js +20 -0
- package/lib/inventory/atomUtils.js +1092 -0
- package/lib/inventory/auditCategories.js +192 -0
- package/lib/inventory/bomUtils.js +369 -0
- package/lib/inventory/cacheCommands.js +182 -0
- package/lib/inventory/cacheDir.js +104 -0
- package/lib/inventory/cbomutils.js +590 -0
- package/lib/inventory/cdxrs.js +434 -0
- package/lib/inventory/ciParsers/azurePipelines.js +295 -0
- package/lib/inventory/ciParsers/circleCi.js +286 -0
- package/lib/inventory/ciParsers/common.js +24 -0
- package/lib/inventory/ciParsers/githubActions.js +2434 -0
- package/lib/inventory/ciParsers/gitlabCi.js +213 -0
- package/lib/inventory/ciParsers/jenkins.js +180 -0
- package/lib/inventory/citations.js +234 -0
- package/lib/inventory/communityAiConfigParser.js +756 -0
- package/lib/inventory/containerRisk.js +204 -0
- package/lib/inventory/cryptoAlgorithmFamily.js +258 -0
- package/lib/inventory/deps.js +807 -0
- package/lib/inventory/depsUtils.js +588 -0
- package/lib/inventory/display.js +2128 -0
- package/lib/inventory/dosai.js +601 -0
- package/lib/inventory/dosaiParsers.js +154 -0
- package/lib/inventory/dynamic.js +145 -0
- package/lib/inventory/envcontext.js +1793 -0
- package/lib/inventory/evidenceUtils.js +774 -0
- package/lib/inventory/fetchBatch.js +779 -0
- package/lib/inventory/fetchRate.js +255 -0
- package/lib/inventory/forgeEnricher.js +300 -0
- package/lib/inventory/formulationParsers.js +422 -0
- package/lib/inventory/gtfobins.js +339 -0
- package/lib/inventory/hbom.js +719 -0
- package/lib/inventory/hbomAnalysis.js +310 -0
- package/lib/inventory/hbomLoader.js +35 -0
- package/lib/inventory/hostTopology.js +835 -0
- package/lib/inventory/inventoryStats.js +100 -0
- package/lib/inventory/jsonLike.js +121 -0
- package/lib/inventory/licenseEnhancer.js +918 -0
- package/lib/inventory/lolbas.js +285 -0
- package/lib/inventory/mcp.js +253 -0
- package/lib/inventory/mcpConfigParser.js +683 -0
- package/lib/inventory/mcpDiscovery.js +112 -0
- package/lib/inventory/mcpPinning.js +209 -0
- package/lib/inventory/osPackageResolver.js +493 -0
- package/lib/inventory/osinfo.js +383 -0
- package/lib/inventory/osqueryTransform.js +274 -0
- package/lib/inventory/plugins.js +466 -0
- package/lib/inventory/protobom.js +231 -0
- package/lib/inventory/protobomLoader.js +43 -0
- package/lib/inventory/provenanceUtils.js +224 -0
- package/lib/inventory/purl.js +749 -0
- package/lib/inventory/rustFormulationParser.js +339 -0
- package/lib/inventory/sbomDocument.js +340 -0
- package/lib/inventory/source.js +1488 -0
- package/lib/inventory/spdx.js +361 -0
- package/lib/inventory/spdxExpression.js +512 -0
- package/lib/inventory/spdxUtils.js +107 -0
- package/lib/inventory/table.js +267 -0
- package/lib/inventory/traceRunner.js +439 -0
- package/lib/inventory/unicodeScan.js +147 -0
- package/lib/managers/binary.js +3459 -0
- package/lib/managers/containerutils.js +125 -0
- package/lib/managers/docker.js +2145 -0
- package/lib/managers/dockerConnection.js +162 -0
- package/lib/managers/oci.js +704 -0
- package/lib/managers/piptree.js +267 -0
- package/lib/parsers/cmakeCache.js +199 -0
- package/lib/parsers/gguf.js +492 -0
- package/lib/parsers/gitAiNotes.js +233 -0
- package/lib/parsers/gitmodules.js +239 -0
- package/lib/parsers/htmlExtract.js +610 -0
- package/lib/parsers/huggingfaceManifest.js +551 -0
- package/lib/parsers/huggingfaceUtils.js +506 -0
- package/lib/parsers/iri.js +618 -0
- package/lib/parsers/npmrc.js +99 -0
- package/lib/parsers/ollama.js +101 -0
- package/lib/parsers/xml.js +841 -0
- package/lib/server/openapi.yaml +433 -0
- package/lib/server/server.js +616 -0
- package/lib/stages/postgen/annotator.js +977 -0
- package/lib/stages/postgen/auditBom.js +468 -0
- package/lib/stages/postgen/postgen.js +1239 -0
- package/lib/stages/postgen/ruleEngine.js +731 -0
- package/lib/stages/postgen/sortBom.js +195 -0
- package/lib/stages/postgen/spdxConverter.js +796 -0
- package/lib/stages/postgen/specVersionCompat.js +703 -0
- package/lib/stages/pregen/envAudit.js +388 -0
- package/lib/stages/pregen/pregen.js +637 -0
- package/lib/third-party/README.md +9 -0
- package/lib/third-party/arborist/CHANGELOG.md +1109 -0
- package/lib/third-party/arborist/LICENSE.md +20 -0
- package/lib/third-party/arborist/README.md +315 -0
- package/lib/third-party/arborist/lib/arborist/index.js +258 -0
- package/lib/third-party/arborist/lib/arborist/load-actual.js +605 -0
- package/lib/third-party/arborist/lib/arborist/load-virtual.js +300 -0
- package/lib/third-party/arborist/lib/bin-links.js +120 -0
- package/lib/third-party/arborist/lib/calc-dep-flags.js +130 -0
- package/lib/third-party/arborist/lib/case-insensitive-map.js +51 -0
- package/lib/third-party/arborist/lib/consistent-resolve.js +42 -0
- package/lib/third-party/arborist/lib/debug.js +50 -0
- package/lib/third-party/arborist/lib/dep-valid.js +190 -0
- package/lib/third-party/arborist/lib/edge.js +417 -0
- package/lib/third-party/arborist/lib/from-path.js +36 -0
- package/lib/third-party/arborist/lib/gather-dep-set.js +43 -0
- package/lib/third-party/arborist/lib/index.js +22 -0
- package/lib/third-party/arborist/lib/inventory.js +138 -0
- package/lib/third-party/arborist/lib/link.js +169 -0
- package/lib/third-party/arborist/lib/node.js +1673 -0
- package/lib/third-party/arborist/lib/npm-extension.js +45 -0
- package/lib/third-party/arborist/lib/override-resolves.js +11 -0
- package/lib/third-party/arborist/lib/override-set.js +319 -0
- package/lib/third-party/arborist/lib/package-extensions.js +289 -0
- package/lib/third-party/arborist/lib/printable.js +210 -0
- package/lib/third-party/arborist/lib/proc-log.js +30 -0
- package/lib/third-party/arborist/lib/realpath.js +100 -0
- package/lib/third-party/arborist/lib/relpath.js +4 -0
- package/lib/third-party/arborist/lib/shrinkwrap.js +1291 -0
- package/lib/third-party/arborist/lib/spec-from-lock.js +34 -0
- package/lib/third-party/arborist/lib/tree-check.js +165 -0
- package/lib/third-party/arborist/lib/validate-npm-package-name.js +107 -0
- package/lib/third-party/arborist/lib/version-from-tgz.js +51 -0
- package/lib/third-party/arborist/lib/yarn-lock.js +397 -0
- package/lib/validator/bomValidator.js +985 -0
- package/lib/validator/complianceEngine.js +241 -0
- package/lib/validator/complianceRules.js +1680 -0
- package/lib/validator/generated/runtime.mjs +17 -0
- package/lib/validator/generated/validate-1.6.mjs +21258 -0
- package/lib/validator/generated/validate-1.7.mjs +24803 -0
- package/lib/validator/generated/validate-2.0.mjs +22931 -0
- package/lib/validator/index.js +246 -0
- package/lib/validator/reporters/annotations.js +142 -0
- package/lib/validator/reporters/console.js +160 -0
- package/lib/validator/reporters/index.js +41 -0
- package/lib/validator/reporters/json.js +37 -0
- package/lib/validator/reporters/sarif.js +184 -0
- package/package.json +209 -26
- package/types/bin/audit.d.ts +3 -0
- package/types/bin/audit.d.ts.map +1 -0
- package/types/bin/cdxgen.d.ts +3 -0
- package/types/bin/cdxgen.d.ts.map +1 -0
- package/types/bin/convert.d.ts +3 -0
- package/types/bin/convert.d.ts.map +1 -0
- package/types/bin/evinse.d.ts +3 -0
- package/types/bin/evinse.d.ts.map +1 -0
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts +3 -0
- package/types/bin/repl.d.ts.map +1 -0
- package/types/bin/sign.d.ts +3 -0
- package/types/bin/sign.d.ts.map +1 -0
- package/types/bin/tracebom.d.ts +3 -0
- package/types/bin/tracebom.d.ts.map +1 -0
- package/types/bin/validate.d.ts +14 -0
- package/types/bin/validate.d.ts.map +1 -0
- package/types/bin/verify.d.ts +3 -0
- package/types/bin/verify.d.ts.map +1 -0
- package/types/lib/audit/index.d.ts +153 -0
- package/types/lib/audit/index.d.ts.map +1 -0
- package/types/lib/audit/progress.d.ts +31 -0
- package/types/lib/audit/progress.d.ts.map +1 -0
- package/types/lib/audit/reporters.d.ts +62 -0
- package/types/lib/audit/reporters.d.ts.map +1 -0
- package/types/lib/audit/scoring.d.ts +36 -0
- package/types/lib/audit/scoring.d.ts.map +1 -0
- package/types/lib/audit/targets.d.ts +77 -0
- package/types/lib/audit/targets.d.ts.map +1 -0
- package/types/lib/cli/bomAssembly.d.ts +329 -0
- package/types/lib/cli/bomAssembly.d.ts.map +1 -0
- package/types/lib/cli/cliOptions.d.ts +156 -0
- package/types/lib/cli/cliOptions.d.ts.map +1 -0
- package/types/lib/cli/index.d.ts +107 -0
- package/types/lib/cli/index.d.ts.map +1 -0
- package/types/lib/cli/jsBom.d.ts +94 -0
- package/types/lib/cli/jsBom.d.ts.map +1 -0
- package/types/lib/cli/jvmBom.d.ts +54 -0
- package/types/lib/cli/jvmBom.d.ts.map +1 -0
- package/types/lib/cli/managedBom.d.ts +105 -0
- package/types/lib/cli/managedBom.d.ts.map +1 -0
- package/types/lib/cli/nativeBom.d.ts +143 -0
- package/types/lib/cli/nativeBom.d.ts.map +1 -0
- package/types/lib/core/activity.d.ts +178 -0
- package/types/lib/core/activity.d.ts.map +1 -0
- package/types/lib/core/env.d.ts +192 -0
- package/types/lib/core/env.d.ts.map +1 -0
- package/types/lib/core/fs.d.ts +158 -0
- package/types/lib/core/fs.d.ts.map +1 -0
- package/types/lib/core/httpClient.d.ts +149 -0
- package/types/lib/core/httpClient.d.ts.map +1 -0
- package/types/lib/core/logger.d.ts +50 -0
- package/types/lib/core/logger.d.ts.map +1 -0
- package/types/lib/core/parallel.d.ts +95 -0
- package/types/lib/core/parallel.d.ts.map +1 -0
- package/types/lib/core/paths.d.ts +36 -0
- package/types/lib/core/paths.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts +23 -0
- package/types/lib/core/projectConfig.d.ts.map +1 -0
- package/types/lib/core/propertySanitizer.d.ts +23 -0
- package/types/lib/core/propertySanitizer.d.ts.map +1 -0
- package/types/lib/core/spdx.d.ts +5 -0
- package/types/lib/core/spdx.d.ts.map +1 -0
- package/types/lib/core/state.d.ts +20 -0
- package/types/lib/core/state.d.ts.map +1 -0
- package/types/lib/core/text.d.ts +78 -0
- package/types/lib/core/text.d.ts.map +1 -0
- package/types/lib/core/ui.d.ts +87 -0
- package/types/lib/core/ui.d.ts.map +1 -0
- package/types/lib/core/urls.d.ts +43 -0
- package/types/lib/core/urls.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts +71 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -0
- package/types/lib/ecosystems/bunutils.d.ts +38 -0
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -0
- package/types/lib/ecosystems/caxa.d.ts +8 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -0
- package/types/lib/ecosystems/chromextutils.d.ts +97 -0
- package/types/lib/ecosystems/chromextutils.d.ts.map +1 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts +176 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +35 -0
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +76 -0
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -0
- package/types/lib/ecosystems/dotnetutils.d.ts +45 -0
- package/types/lib/ecosystems/dotnetutils.d.ts.map +1 -0
- package/types/lib/ecosystems/ecosystems.d.ts +279 -0
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -0
- package/types/lib/ecosystems/golem.d.ts +60 -0
- package/types/lib/ecosystems/golem.d.ts.map +1 -0
- package/types/lib/ecosystems/gradleutils.d.ts +139 -0
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -0
- package/types/lib/ecosystems/jsEvidence.d.ts +17 -0
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -0
- package/types/lib/ecosystems/npmutils.d.ts +183 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts +36 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts +116 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-gleam.d.ts +33 -0
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-go.d.ts +92 -0
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-js.d.ts +242 -0
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-jvm.d.ts +100 -0
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-misc.d.ts +450 -0
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-python.d.ts +145 -0
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rust.d.ts +56 -0
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-zig.d.ts +83 -0
- package/types/lib/ecosystems/parsers-zig.d.ts.map +1 -0
- package/types/lib/ecosystems/pep770.d.ts +38 -0
- package/types/lib/ecosystems/pep770.d.ts.map +1 -0
- package/types/lib/ecosystems/pylockutils.d.ts +68 -0
- package/types/lib/ecosystems/pylockutils.d.ts.map +1 -0
- package/types/lib/ecosystems/pythonutils.d.ts +70 -0
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -0
- package/types/lib/ecosystems/registryProvenance.d.ts +26 -0
- package/types/lib/ecosystems/registryProvenance.d.ts.map +1 -0
- package/types/lib/ecosystems/remote/huggingface.d.ts +31 -0
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -0
- package/types/lib/ecosystems/rubyutils.d.ts +182 -0
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -0
- package/types/lib/ecosystems/rusi.d.ts +40 -0
- package/types/lib/ecosystems/rusi.d.ts.map +1 -0
- package/types/lib/ecosystems/sbtutils.d.ts +179 -0
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -0
- package/types/lib/ecosystems/tea.d.ts +180 -0
- package/types/lib/ecosystems/tea.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +41 -0
- package/types/lib/ecosystems/utils.d.ts.map +1 -0
- package/types/lib/ecosystems/zigResolver.d.ts +70 -0
- package/types/lib/ecosystems/zigResolver.d.ts.map +1 -0
- package/types/lib/evinser/db.d.ts +17 -0
- package/types/lib/evinser/db.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +354 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -0
- package/types/lib/evinser/scalasem.d.ts +15 -0
- package/types/lib/evinser/scalasem.d.ts.map +1 -0
- package/types/lib/evinser/swiftsem.d.ts +103 -0
- package/types/lib/evinser/swiftsem.d.ts.map +1 -0
- package/types/lib/helpers/annotationFormatter.d.ts +23 -0
- package/types/lib/helpers/annotationFormatter.d.ts.map +1 -0
- package/types/lib/helpers/bomSigner.d.ts +28 -0
- package/types/lib/helpers/bomSigner.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts +52 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -0
- package/types/lib/helpers/remote/dependency-track.d.ts +23 -0
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
- package/types/lib/helpers/versutils.d.ts +8 -0
- package/types/lib/helpers/versutils.d.ts.map +1 -0
- package/types/lib/helpers/vsixutils.d.ts +130 -0
- package/types/lib/helpers/vsixutils.d.ts.map +1 -0
- package/types/lib/inventory/agentFormulationParser.d.ts +21 -0
- package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -0
- package/types/lib/inventory/aiCollector.d.ts +61 -0
- package/types/lib/inventory/aiCollector.d.ts.map +1 -0
- package/types/lib/inventory/aiInventory.d.ts +103 -0
- package/types/lib/inventory/aiInventory.d.ts.map +1 -0
- package/types/lib/inventory/aiModelVariants.d.ts +31 -0
- package/types/lib/inventory/aiModelVariants.d.ts.map +1 -0
- package/types/lib/inventory/aiOversightCollector.d.ts +28 -0
- package/types/lib/inventory/aiOversightCollector.d.ts.map +1 -0
- package/types/lib/inventory/aiProvenanceCollector.d.ts +13 -0
- package/types/lib/inventory/aiProvenanceCollector.d.ts.map +1 -0
- package/types/lib/inventory/analyzer.d.ts +157 -0
- package/types/lib/inventory/analyzer.d.ts.map +1 -0
- package/types/lib/inventory/analyzerScope.d.ts +106 -0
- package/types/lib/inventory/analyzerScope.d.ts.map +1 -0
- package/types/lib/inventory/astWorker.d.ts +9 -0
- package/types/lib/inventory/astWorker.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +159 -0
- package/types/lib/inventory/atomUtils.d.ts.map +1 -0
- package/types/lib/inventory/auditCategories.d.ts +80 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -0
- package/types/lib/inventory/bomUtils.d.ts +145 -0
- package/types/lib/inventory/bomUtils.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +28 -0
- package/types/lib/inventory/cacheCommands.d.ts.map +1 -0
- package/types/lib/inventory/cacheDir.d.ts +55 -0
- package/types/lib/inventory/cacheDir.d.ts.map +1 -0
- package/types/lib/inventory/cbomutils.d.ts +37 -0
- package/types/lib/inventory/cbomutils.d.ts.map +1 -0
- package/types/lib/inventory/cdxrs.d.ts +90 -0
- package/types/lib/inventory/cdxrs.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/azurePipelines.d.ts +27 -0
- package/types/lib/inventory/ciParsers/azurePipelines.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/circleCi.d.ts +27 -0
- package/types/lib/inventory/ciParsers/circleCi.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/common.d.ts +11 -0
- package/types/lib/inventory/ciParsers/common.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/githubActions.d.ts +38 -0
- package/types/lib/inventory/ciParsers/githubActions.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/gitlabCi.d.ts +26 -0
- package/types/lib/inventory/ciParsers/gitlabCi.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/jenkins.d.ts +26 -0
- package/types/lib/inventory/ciParsers/jenkins.d.ts.map +1 -0
- package/types/lib/inventory/citations.d.ts +90 -0
- package/types/lib/inventory/citations.d.ts.map +1 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts +14 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -0
- package/types/lib/inventory/containerRisk.d.ts +20 -0
- package/types/lib/inventory/containerRisk.d.ts.map +1 -0
- package/types/lib/inventory/cryptoAlgorithmFamily.d.ts +37 -0
- package/types/lib/inventory/cryptoAlgorithmFamily.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +140 -0
- package/types/lib/inventory/deps.d.ts.map +1 -0
- package/types/lib/inventory/depsUtils.d.ts +74 -0
- package/types/lib/inventory/depsUtils.d.ts.map +1 -0
- package/types/lib/inventory/display.d.ts +227 -0
- package/types/lib/inventory/display.d.ts.map +1 -0
- package/types/lib/inventory/dosai.d.ts +130 -0
- package/types/lib/inventory/dosai.d.ts.map +1 -0
- package/types/lib/inventory/dosaiParsers.d.ts +59 -0
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -0
- package/types/lib/inventory/dynamic.d.ts +25 -0
- package/types/lib/inventory/dynamic.d.ts.map +1 -0
- package/types/lib/inventory/envcontext.d.ts +377 -0
- package/types/lib/inventory/envcontext.d.ts.map +1 -0
- package/types/lib/inventory/evidenceUtils.d.ts +74 -0
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -0
- package/types/lib/inventory/fetchBatch.d.ts +127 -0
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -0
- package/types/lib/inventory/fetchRate.d.ts +118 -0
- package/types/lib/inventory/fetchRate.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts +31 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -0
- package/types/lib/inventory/formulationParsers.d.ts +50 -0
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -0
- package/types/lib/inventory/gtfobins.d.ts +27 -0
- package/types/lib/inventory/gtfobins.d.ts.map +1 -0
- package/types/lib/inventory/hbom.d.ts +58 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -0
- package/types/lib/inventory/hbomAnalysis.d.ts +56 -0
- package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/inventory/hbomLoader.d.ts +7 -0
- package/types/lib/inventory/hbomLoader.d.ts.map +1 -0
- package/types/lib/inventory/hostTopology.d.ts +47 -0
- package/types/lib/inventory/hostTopology.d.ts.map +1 -0
- package/types/lib/inventory/inventoryStats.d.ts +42 -0
- package/types/lib/inventory/inventoryStats.d.ts.map +1 -0
- package/types/lib/inventory/jsonLike.d.ts +23 -0
- package/types/lib/inventory/jsonLike.d.ts.map +1 -0
- package/types/lib/inventory/licenseEnhancer.d.ts +70 -0
- package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -0
- package/types/lib/inventory/lolbas.d.ts +16 -0
- package/types/lib/inventory/lolbas.d.ts.map +1 -0
- package/types/lib/inventory/mcp.d.ts +29 -0
- package/types/lib/inventory/mcp.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts +20 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -0
- package/types/lib/inventory/mcpDiscovery.d.ts +33 -0
- package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -0
- package/types/lib/inventory/mcpPinning.d.ts +11 -0
- package/types/lib/inventory/mcpPinning.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +49 -0
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -0
- package/types/lib/inventory/osinfo.d.ts +201 -0
- package/types/lib/inventory/osinfo.d.ts.map +1 -0
- package/types/lib/inventory/osqueryTransform.d.ts +84 -0
- package/types/lib/inventory/osqueryTransform.d.ts.map +1 -0
- package/types/lib/inventory/plugins.d.ts +58 -0
- package/types/lib/inventory/plugins.d.ts.map +1 -0
- package/types/lib/inventory/protobom.d.ts +71 -0
- package/types/lib/inventory/protobom.d.ts.map +1 -0
- package/types/lib/inventory/protobomLoader.d.ts +17 -0
- package/types/lib/inventory/protobomLoader.d.ts.map +1 -0
- package/types/lib/inventory/provenanceUtils.d.ts +98 -0
- package/types/lib/inventory/provenanceUtils.d.ts.map +1 -0
- package/types/lib/inventory/purl.d.ts +313 -0
- package/types/lib/inventory/purl.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts +17 -0
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -0
- package/types/lib/inventory/sbomDocument.d.ts +59 -0
- package/types/lib/inventory/sbomDocument.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +163 -0
- package/types/lib/inventory/source.d.ts.map +1 -0
- package/types/lib/inventory/spdx.d.ts +66 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -0
- package/types/lib/inventory/spdxExpression.d.ts +58 -0
- package/types/lib/inventory/spdxExpression.d.ts.map +1 -0
- package/types/lib/inventory/spdxUtils.d.ts +12 -0
- package/types/lib/inventory/spdxUtils.d.ts.map +1 -0
- package/types/lib/inventory/table.d.ts +22 -0
- package/types/lib/inventory/table.d.ts.map +1 -0
- package/types/lib/inventory/traceRunner.d.ts +80 -0
- package/types/lib/inventory/traceRunner.d.ts.map +1 -0
- package/types/lib/inventory/unicodeScan.d.ts +46 -0
- package/types/lib/inventory/unicodeScan.d.ts.map +1 -0
- package/types/lib/managers/binary.d.ts +147 -0
- package/types/lib/managers/binary.d.ts.map +1 -0
- package/types/lib/managers/containerutils.d.ts +30 -0
- package/types/lib/managers/containerutils.d.ts.map +1 -0
- package/types/lib/managers/docker.d.ts +157 -0
- package/types/lib/managers/docker.d.ts.map +1 -0
- package/types/lib/managers/dockerConnection.d.ts +42 -0
- package/types/lib/managers/dockerConnection.d.ts.map +1 -0
- package/types/lib/managers/oci.d.ts +21 -0
- package/types/lib/managers/oci.d.ts.map +1 -0
- package/types/lib/managers/piptree.d.ts +13 -0
- package/types/lib/managers/piptree.d.ts.map +1 -0
- package/types/lib/parsers/cmakeCache.d.ts +70 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -0
- package/types/lib/parsers/gguf.d.ts +39 -0
- package/types/lib/parsers/gguf.d.ts.map +1 -0
- package/types/lib/parsers/gitAiNotes.d.ts +15 -0
- package/types/lib/parsers/gitAiNotes.d.ts.map +1 -0
- package/types/lib/parsers/gitmodules.d.ts +88 -0
- package/types/lib/parsers/gitmodules.d.ts.map +1 -0
- package/types/lib/parsers/htmlExtract.d.ts +34 -0
- package/types/lib/parsers/htmlExtract.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceManifest.d.ts +153 -0
- package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts +155 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -0
- package/types/lib/parsers/iri.d.ts +68 -0
- package/types/lib/parsers/iri.d.ts.map +1 -0
- package/types/lib/parsers/npmrc.d.ts +33 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -0
- package/types/lib/parsers/ollama.d.ts +22 -0
- package/types/lib/parsers/ollama.d.ts.map +1 -0
- package/types/lib/parsers/xml.d.ts +47 -0
- package/types/lib/parsers/xml.d.ts.map +1 -0
- package/types/lib/server/server.d.ts +51 -0
- package/types/lib/server/server.d.ts.map +1 -0
- package/types/lib/stages/postgen/annotator.d.ts +36 -0
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -0
- package/types/lib/stages/postgen/auditBom.d.ts +92 -0
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/postgen.d.ts +59 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
- package/types/lib/stages/postgen/sortBom.d.ts +34 -0
- package/types/lib/stages/postgen/sortBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts +11 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts.map +1 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts +71 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -0
- package/types/lib/stages/pregen/envAudit.d.ts +14 -0
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
- package/types/lib/stages/pregen/pregen.d.ts +59 -0
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts +47 -0
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts +4 -0
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts +4 -0
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/bin-links.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/bin-links.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts +9 -0
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/debug.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/debug.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/dep-valid.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/dep-valid.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/edge.d.ts +46 -0
- package/types/lib/third-party/arborist/lib/edge.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/from-path.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/from-path.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/index.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/index.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/inventory.d.ts +14 -0
- package/types/lib/third-party/arborist/lib/inventory.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/link.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/link.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/node.d.ts +112 -0
- package/types/lib/third-party/arborist/lib/node.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/npm-extension.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/npm-extension.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/override-resolves.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/override-resolves.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/override-set.d.ts +27 -0
- package/types/lib/third-party/arborist/lib/override-set.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/package-extensions.d.ts +36 -0
- package/types/lib/third-party/arborist/lib/package-extensions.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/printable.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/printable.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/proc-log.d.ts +20 -0
- package/types/lib/third-party/arborist/lib/proc-log.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/realpath.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/realpath.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/relpath.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/relpath.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts +54 -0
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/tree-check.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/tree-check.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts +13 -0
- package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts +6 -0
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts +35 -0
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts.map +1 -0
- package/types/lib/validator/bomValidator.d.ts +40 -0
- package/types/lib/validator/bomValidator.d.ts.map +1 -0
- package/types/lib/validator/complianceEngine.d.ts +72 -0
- package/types/lib/validator/complianceEngine.d.ts.map +1 -0
- package/types/lib/validator/complianceRules.d.ts +61 -0
- package/types/lib/validator/complianceRules.d.ts.map +1 -0
- package/types/lib/validator/index.d.ts +101 -0
- package/types/lib/validator/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/annotations.d.ts +37 -0
- package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
- package/types/lib/validator/reporters/console.d.ts +34 -0
- package/types/lib/validator/reporters/console.d.ts.map +1 -0
- package/types/lib/validator/reporters/index.d.ts +30 -0
- package/types/lib/validator/reporters/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/json.d.ts +11 -0
- package/types/lib/validator/reporters/json.d.ts.map +1 -0
- package/types/lib/validator/reporters/sarif.d.ts +22 -0
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
- package/mod.d.ts +0 -7
- package/mod.js +0 -22
package/lib/core/fs.js
ADDED
|
@@ -0,0 +1,1058 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
4
|
+
import {
|
|
5
|
+
copyFileSync,
|
|
6
|
+
createReadStream,
|
|
7
|
+
existsSync,
|
|
8
|
+
lstatSync,
|
|
9
|
+
mkdirSync,
|
|
10
|
+
mkdtempSync,
|
|
11
|
+
rmSync,
|
|
12
|
+
unlinkSync,
|
|
13
|
+
writeFileSync,
|
|
14
|
+
} from "node:fs";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
16
|
+
import path, { basename, dirname, join, resolve } from "node:path";
|
|
17
|
+
import process from "node:process";
|
|
18
|
+
|
|
19
|
+
import { Glob, globSync } from "glob";
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
buildReadCountSuffix,
|
|
23
|
+
classifyActivityPath,
|
|
24
|
+
classifyDiscoveryPattern,
|
|
25
|
+
createDryRunError,
|
|
26
|
+
DEBUG_MODE,
|
|
27
|
+
isDryRun,
|
|
28
|
+
isSecureMode,
|
|
29
|
+
readEnvironmentVariable,
|
|
30
|
+
recordActivity,
|
|
31
|
+
recordDiscoveryActivity,
|
|
32
|
+
recordFilesystemActivity,
|
|
33
|
+
recordObservedActivity,
|
|
34
|
+
recordPolicyActivity,
|
|
35
|
+
} from "./activity.js";
|
|
36
|
+
import { thoughtLog, traceLog } from "./logger.js";
|
|
37
|
+
import { isWin } from "./paths.js";
|
|
38
|
+
|
|
39
|
+
function getArchiveSourceByteSize(sourcePath) {
|
|
40
|
+
if (!sourcePath || !safeExistsSync(sourcePath)) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const sourceStats = lstatSync(sourcePath);
|
|
45
|
+
return sourceStats.isFile() ? sourceStats.size : undefined;
|
|
46
|
+
} catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function hasReadPermission(filePath) {
|
|
52
|
+
if (!(isSecureMode && process.permission)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return process.permission.has("fs.read", join(filePath, "", "*"));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function hasWritePermission(filePath) {
|
|
59
|
+
if (!(isSecureMode && process.permission)) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
const candidatePaths = [
|
|
63
|
+
filePath,
|
|
64
|
+
join(filePath, "", "*"),
|
|
65
|
+
join(dirname(filePath), "*"),
|
|
66
|
+
];
|
|
67
|
+
return candidatePaths.some((candidatePath) =>
|
|
68
|
+
process.permission.has("fs.write", candidatePath),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Safely check if a file path exists without crashing due to a lack of permissions
|
|
73
|
+
*
|
|
74
|
+
* @param {String} filePath File path
|
|
75
|
+
* @Boolean True if the path exists. False otherwise
|
|
76
|
+
*/
|
|
77
|
+
export function safeExistsSync(filePath) {
|
|
78
|
+
const pathMetadata = classifyActivityPath(filePath);
|
|
79
|
+
if (!hasReadPermission(filePath)) {
|
|
80
|
+
if (DEBUG_MODE) {
|
|
81
|
+
console.log("cdxgen lacks read permission for a requested path.");
|
|
82
|
+
}
|
|
83
|
+
if (pathMetadata) {
|
|
84
|
+
recordPolicyActivity(filePath, {
|
|
85
|
+
metadata: {
|
|
86
|
+
classification: pathMetadata.classification,
|
|
87
|
+
ecosystem: pathMetadata.ecosystem,
|
|
88
|
+
policyType: "fs.read",
|
|
89
|
+
},
|
|
90
|
+
reason: `Denied inspection of ${pathMetadata.label} ${filePath} due to missing fs.read permission.`,
|
|
91
|
+
status: "blocked",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
const exists = existsSync(filePath);
|
|
97
|
+
if (pathMetadata) {
|
|
98
|
+
const inspectionKind =
|
|
99
|
+
pathMetadata.classification === "directory" ? "discover" : "inspect";
|
|
100
|
+
recordObservedActivity(inspectionKind, filePath, {
|
|
101
|
+
metadata: {
|
|
102
|
+
classification: pathMetadata.classification,
|
|
103
|
+
ecosystem: pathMetadata.ecosystem,
|
|
104
|
+
exists,
|
|
105
|
+
redacted: pathMetadata.sensitive ?? false,
|
|
106
|
+
},
|
|
107
|
+
reasonBuilder: (count) =>
|
|
108
|
+
`${exists ? "Inspected" : "Checked for"} ${pathMetadata.label} ${filePath}${buildReadCountSuffix(count)}.`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return exists;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Permission- and dry-run-aware wrapper around writeFileSync. Records the
|
|
116
|
+
* activity and returns undefined when blocked.
|
|
117
|
+
*
|
|
118
|
+
* @param {string} filePath File path to write.
|
|
119
|
+
* @param {string|Buffer} data Data to write.
|
|
120
|
+
* @param {Object} [options] writeFileSync options (encoding, mode, flag).
|
|
121
|
+
* @returns {void}
|
|
122
|
+
*/
|
|
123
|
+
export function safeWriteSync(filePath, data, options) {
|
|
124
|
+
if (isDryRun) {
|
|
125
|
+
recordFilesystemActivity(
|
|
126
|
+
"write",
|
|
127
|
+
filePath,
|
|
128
|
+
"blocked",
|
|
129
|
+
"Dry run mode blocks filesystem writes.",
|
|
130
|
+
);
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
if (!hasWritePermission(filePath)) {
|
|
134
|
+
if (DEBUG_MODE) {
|
|
135
|
+
console.log("cdxgen lacks write permission for a requested path.");
|
|
136
|
+
}
|
|
137
|
+
recordFilesystemActivity(
|
|
138
|
+
"write",
|
|
139
|
+
filePath,
|
|
140
|
+
"blocked",
|
|
141
|
+
"cdxgen lacks write permission for this path.",
|
|
142
|
+
);
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
writeFileSync(filePath, data, options);
|
|
146
|
+
recordFilesystemActivity("write", filePath, "completed");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Safely create a directory without crashing due to a lack of permissions
|
|
151
|
+
*
|
|
152
|
+
* @param {String} filePath File path
|
|
153
|
+
* @param options {Options} mkdir options
|
|
154
|
+
* @Boolean True if the path exists. False otherwise
|
|
155
|
+
*/
|
|
156
|
+
export function safeMkdirSync(filePath, options) {
|
|
157
|
+
if (isDryRun) {
|
|
158
|
+
recordFilesystemActivity(
|
|
159
|
+
"mkdir",
|
|
160
|
+
filePath,
|
|
161
|
+
"blocked",
|
|
162
|
+
"Dry run mode blocks directory creation.",
|
|
163
|
+
);
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
if (!hasWritePermission(filePath)) {
|
|
167
|
+
if (DEBUG_MODE) {
|
|
168
|
+
console.log("cdxgen lacks write permission for a requested path.");
|
|
169
|
+
}
|
|
170
|
+
recordFilesystemActivity(
|
|
171
|
+
"mkdir",
|
|
172
|
+
filePath,
|
|
173
|
+
"blocked",
|
|
174
|
+
"cdxgen lacks write permission for this path.",
|
|
175
|
+
);
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
mkdirSync(filePath, options);
|
|
179
|
+
recordFilesystemActivity("mkdir", filePath, "completed");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Dry-run-aware wrapper around mkdtempSync that records the activity. In dry-run
|
|
184
|
+
* mode, returns a synthetic path without touching the filesystem.
|
|
185
|
+
*
|
|
186
|
+
* @param {string} prefix Path prefix for the temporary directory.
|
|
187
|
+
* @param {string|Object} [options] Encoding or mkdtempSync options.
|
|
188
|
+
* @returns {string|undefined} The created directory path, a synthetic path in dry-run mode, or undefined when blocked.
|
|
189
|
+
*/
|
|
190
|
+
export function safeMkdtempSync(prefix, options = undefined) {
|
|
191
|
+
const resourceType =
|
|
192
|
+
typeof prefix === "string" && prefix.toLowerCase().includes("cache")
|
|
193
|
+
? "cache"
|
|
194
|
+
: "temporary-workspace";
|
|
195
|
+
if (isDryRun) {
|
|
196
|
+
const tempPath = `${prefix}${randomUUID().replaceAll("-", "").slice(0, 6)}`;
|
|
197
|
+
recordFilesystemActivity(
|
|
198
|
+
"temp-dir",
|
|
199
|
+
tempPath,
|
|
200
|
+
"blocked",
|
|
201
|
+
`Dry run mode blocks temporary directory creation for ${resourceType}.`,
|
|
202
|
+
{
|
|
203
|
+
resourceType,
|
|
204
|
+
},
|
|
205
|
+
);
|
|
206
|
+
return tempPath;
|
|
207
|
+
}
|
|
208
|
+
const tempPath = mkdtempSync(prefix, options);
|
|
209
|
+
recordFilesystemActivity("temp-dir", tempPath, "completed", undefined, {
|
|
210
|
+
resourceType,
|
|
211
|
+
});
|
|
212
|
+
return tempPath;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Dry-run-aware wrapper around rmSync. Records the activity and returns
|
|
217
|
+
* undefined when blocked.
|
|
218
|
+
*
|
|
219
|
+
* @param {string} filePath Path to remove.
|
|
220
|
+
* @param {Object} [options] rmSync options (recursive, force, etc.).
|
|
221
|
+
* @returns {void}
|
|
222
|
+
*/
|
|
223
|
+
export function safeRmSync(filePath, options = undefined) {
|
|
224
|
+
if (isDryRun) {
|
|
225
|
+
recordFilesystemActivity(
|
|
226
|
+
"cleanup",
|
|
227
|
+
filePath,
|
|
228
|
+
"blocked",
|
|
229
|
+
"Dry run mode blocks filesystem deletions.",
|
|
230
|
+
);
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
rmSync(filePath, options);
|
|
234
|
+
recordFilesystemActivity("cleanup", filePath, "completed");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Dry-run-aware wrapper around unlinkSync. Records the activity and returns
|
|
239
|
+
* undefined when blocked.
|
|
240
|
+
*
|
|
241
|
+
* @param {string} filePath File path to unlink.
|
|
242
|
+
* @returns {void}
|
|
243
|
+
*/
|
|
244
|
+
export function safeUnlinkSync(filePath) {
|
|
245
|
+
if (isDryRun) {
|
|
246
|
+
recordFilesystemActivity(
|
|
247
|
+
"cleanup",
|
|
248
|
+
filePath,
|
|
249
|
+
"blocked",
|
|
250
|
+
"Dry run mode blocks file deletions.",
|
|
251
|
+
);
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
unlinkSync(filePath);
|
|
255
|
+
recordFilesystemActivity("cleanup", filePath, "completed");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Dry-run-aware wrapper around copyFileSync. Records the activity and returns
|
|
260
|
+
* undefined when blocked.
|
|
261
|
+
*
|
|
262
|
+
* @param {string} src Source file path.
|
|
263
|
+
* @param {string} dest Destination file path.
|
|
264
|
+
* @param {number} [mode] Optional copy mode bitmask.
|
|
265
|
+
* @returns {void}
|
|
266
|
+
*/
|
|
267
|
+
export function safeCopyFileSync(src, dest, mode = undefined) {
|
|
268
|
+
if (isDryRun) {
|
|
269
|
+
recordFilesystemActivity(
|
|
270
|
+
"write",
|
|
271
|
+
dest,
|
|
272
|
+
"blocked",
|
|
273
|
+
`Dry run mode blocks copying files from ${src}.`,
|
|
274
|
+
);
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
const result =
|
|
278
|
+
mode === undefined
|
|
279
|
+
? copyFileSync(src, dest)
|
|
280
|
+
: copyFileSync(src, dest, mode);
|
|
281
|
+
recordFilesystemActivity("write", dest, "completed", `Copied from ${src}.`);
|
|
282
|
+
return result;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Run an archive extractor under dry-run/debug activity tracing. In dry-run
|
|
287
|
+
* mode the extraction is recorded as blocked and resolves false without running.
|
|
288
|
+
*
|
|
289
|
+
* @param {string} sourcePath Path to the source archive.
|
|
290
|
+
* @param {string} targetPath Path to extract into.
|
|
291
|
+
* @param {() => Promise} extractor Async function performing the extraction.
|
|
292
|
+
* @param {string} [kind="unzip"] Archive kind label for tracing.
|
|
293
|
+
* @param {Object} [options] Optional tracing metadata, blockedReason, and failureReason.
|
|
294
|
+
* @returns {Promise<boolean>} True when extraction succeeded, false when blocked by dry-run.
|
|
295
|
+
*/
|
|
296
|
+
export async function safeExtractArchive(
|
|
297
|
+
sourcePath,
|
|
298
|
+
targetPath,
|
|
299
|
+
extractor,
|
|
300
|
+
kind = "unzip",
|
|
301
|
+
options = undefined,
|
|
302
|
+
) {
|
|
303
|
+
const traceArchiveStats = isDryRun || DEBUG_MODE;
|
|
304
|
+
const sourceBytes = traceArchiveStats
|
|
305
|
+
? getArchiveSourceByteSize(sourcePath)
|
|
306
|
+
: undefined;
|
|
307
|
+
if (isDryRun) {
|
|
308
|
+
recordActivity({
|
|
309
|
+
archiveKind: kind,
|
|
310
|
+
capability: "archive-extraction",
|
|
311
|
+
kind,
|
|
312
|
+
...(options?.metadata || {}),
|
|
313
|
+
...(sourceBytes !== undefined ? { sourceBytes } : {}),
|
|
314
|
+
reason:
|
|
315
|
+
options?.blockedReason ||
|
|
316
|
+
`Dry run mode blocks ${kind} extraction from ${sourcePath} into ${targetPath}.`,
|
|
317
|
+
status: "blocked",
|
|
318
|
+
target: `${sourcePath} -> ${targetPath}`,
|
|
319
|
+
});
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
await extractor();
|
|
324
|
+
recordActivity({
|
|
325
|
+
archiveKind: kind,
|
|
326
|
+
capability: "archive-extraction",
|
|
327
|
+
kind,
|
|
328
|
+
...(options?.metadata || {}),
|
|
329
|
+
...(sourceBytes !== undefined ? { sourceBytes } : {}),
|
|
330
|
+
status: "completed",
|
|
331
|
+
target: `${sourcePath} -> ${targetPath}`,
|
|
332
|
+
});
|
|
333
|
+
return true;
|
|
334
|
+
} catch (error) {
|
|
335
|
+
recordActivity({
|
|
336
|
+
archiveKind: kind,
|
|
337
|
+
capability: "archive-extraction",
|
|
338
|
+
kind,
|
|
339
|
+
...(options?.metadata || {}),
|
|
340
|
+
...(sourceBytes !== undefined ? { sourceBytes } : {}),
|
|
341
|
+
...(error?.code ? { errorCode: error.code } : {}),
|
|
342
|
+
reason:
|
|
343
|
+
options?.failureReason ||
|
|
344
|
+
`Failed ${kind} extraction from ${sourcePath} into ${targetPath}: ${error.message}`,
|
|
345
|
+
status: "failed",
|
|
346
|
+
target: `${sourcePath} -> ${targetPath}`,
|
|
347
|
+
});
|
|
348
|
+
throw error;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Set of temporary file paths written by cdxgen that are removed on process exit. */
|
|
353
|
+
export const temporaryFiles = new Set();
|
|
354
|
+
process.on("exit", () =>
|
|
355
|
+
temporaryFiles.forEach((tempFile) => {
|
|
356
|
+
if (safeExistsSync(tempFile)) {
|
|
357
|
+
safeUnlinkSync(tempFile);
|
|
358
|
+
}
|
|
359
|
+
}),
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
/** Set accumulating every executable command spawned via safeSpawnSync. */
|
|
363
|
+
export const commandsExecuted = new Set();
|
|
364
|
+
function isAllowedCommand(
|
|
365
|
+
command,
|
|
366
|
+
allowedCommandsEnv = readEnvironmentVariable("CDXGEN_ALLOWED_COMMANDS"),
|
|
367
|
+
) {
|
|
368
|
+
if (!allowedCommandsEnv) {
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
return allowedCommandsEnv
|
|
372
|
+
.split(",")
|
|
373
|
+
.map((entry) => entry.trim())
|
|
374
|
+
.includes(command.trim());
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const ALLOWED_WRAPPERS = new Set(["gradlew", "mvnw"]);
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Check for Windows CWD executable hijack when shell: true is used.
|
|
381
|
+
* cmd.exe searches CWD before PATH, allowing local files to shadow system commands.
|
|
382
|
+
*
|
|
383
|
+
* @param {string} command The executable to spawn
|
|
384
|
+
* @param {Object} options Options forwarded to spawnSync (e.g. cwd, env, shell)
|
|
385
|
+
*
|
|
386
|
+
* @returns {boolean} true if there is a hijack risk. false otherwise.
|
|
387
|
+
*/
|
|
388
|
+
function isWindowsShellHijackRisk(command, options) {
|
|
389
|
+
const cwd = options?.cwd;
|
|
390
|
+
const usesShell = options?.shell === true;
|
|
391
|
+
if (!isWin || !usesShell || !cwd || !command) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
if (/[\/\\]/.test(command)) {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
const cmdBase = command.toLowerCase();
|
|
398
|
+
if (ALLOWED_WRAPPERS.has(cmdBase)) {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
const pathExt = (
|
|
402
|
+
readEnvironmentVariable("PATHEXT") ||
|
|
403
|
+
".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC"
|
|
404
|
+
)
|
|
405
|
+
.split(";")
|
|
406
|
+
.filter(Boolean);
|
|
407
|
+
const candidates = [
|
|
408
|
+
cmdBase,
|
|
409
|
+
...pathExt.map((ext) => cmdBase + ext.toLowerCase()),
|
|
410
|
+
];
|
|
411
|
+
const absCwd = resolve(cwd);
|
|
412
|
+
for (const candidate of candidates) {
|
|
413
|
+
const candidatePath = path.join(absCwd, candidate);
|
|
414
|
+
if (existsSync(candidatePath)) {
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const VERSION_PROBE_ARGS = new Set(["--version", "-version", "version"]);
|
|
422
|
+
|
|
423
|
+
const POSIX_SHELL_METACHARACTERS = /[;&|<>$`\\\n\r]/;
|
|
424
|
+
const WINDOWS_SHELL_METACHARACTERS = /[&|<>^%\n\r]/;
|
|
425
|
+
|
|
426
|
+
function hasShellMetacharacters(value) {
|
|
427
|
+
if (value === undefined || value === null) {
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
const stringValue = String(value);
|
|
431
|
+
return isWin
|
|
432
|
+
? WINDOWS_SHELL_METACHARACTERS.test(stringValue)
|
|
433
|
+
: POSIX_SHELL_METACHARACTERS.test(stringValue);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function getUnsafeShellToken(command, args) {
|
|
437
|
+
if (hasShellMetacharacters(command)) {
|
|
438
|
+
return command;
|
|
439
|
+
}
|
|
440
|
+
const argList = Array.isArray(args)
|
|
441
|
+
? args
|
|
442
|
+
: args === undefined || args === null
|
|
443
|
+
? []
|
|
444
|
+
: [args];
|
|
445
|
+
return argList.find((arg) => hasShellMetacharacters(arg));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function recordSuspiciousShellPathActivities(files, metadata = {}) {
|
|
449
|
+
for (const file of files) {
|
|
450
|
+
if (!hasShellMetacharacters(file)) {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
recordActivity({
|
|
454
|
+
classification: "suspicious-path",
|
|
455
|
+
discoveryType: metadata.discoveryType,
|
|
456
|
+
kind: "inspect",
|
|
457
|
+
pattern: metadata.pattern,
|
|
458
|
+
reason:
|
|
459
|
+
"Suspicious path contains shell metacharacters. cdxgen passes direct process arguments as argv values, but review this path before invoking external build tools on untrusted projects.",
|
|
460
|
+
risk: "shell-metacharacters",
|
|
461
|
+
status: "completed",
|
|
462
|
+
target: file,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function detectProbeType(command, args = []) {
|
|
468
|
+
const normalizedCommand = basename(String(command || "")).toLowerCase();
|
|
469
|
+
const normalizedArgs = (args || []).map((arg) => String(arg).toLowerCase());
|
|
470
|
+
if (
|
|
471
|
+
normalizedArgs.some((arg) => VERSION_PROBE_ARGS.has(arg)) ||
|
|
472
|
+
(normalizedArgs.length === 1 && normalizedArgs[0] === "-v")
|
|
473
|
+
) {
|
|
474
|
+
return "version-check";
|
|
475
|
+
}
|
|
476
|
+
if (normalizedCommand === "which" || normalizedArgs.includes("--help")) {
|
|
477
|
+
return "capability-probe";
|
|
478
|
+
}
|
|
479
|
+
if (
|
|
480
|
+
normalizedCommand.startsWith("python") &&
|
|
481
|
+
normalizedArgs.includes("-c") &&
|
|
482
|
+
normalizedArgs.some((arg) => arg.includes("import"))
|
|
483
|
+
) {
|
|
484
|
+
return "runtime-probe";
|
|
485
|
+
}
|
|
486
|
+
return undefined;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function buildCommandActivityDescriptor(command, args, options) {
|
|
490
|
+
const target = `${command}${args?.length ? ` ${args.join(" ")}` : ""}`;
|
|
491
|
+
const cdxgenActivity = options?.cdxgenActivity || {};
|
|
492
|
+
const probeType = cdxgenActivity.probeType || detectProbeType(command, args);
|
|
493
|
+
const metadata = {
|
|
494
|
+
...(cdxgenActivity.metadata || {}),
|
|
495
|
+
};
|
|
496
|
+
if (probeType) {
|
|
497
|
+
metadata.capability = metadata.capability || "tool-runtime-probe";
|
|
498
|
+
metadata.probeType = probeType;
|
|
499
|
+
}
|
|
500
|
+
if (cdxgenActivity.gitOperation) {
|
|
501
|
+
metadata.gitOperation = cdxgenActivity.gitOperation;
|
|
502
|
+
}
|
|
503
|
+
return {
|
|
504
|
+
blockedReason:
|
|
505
|
+
cdxgenActivity.blockedReason ||
|
|
506
|
+
(probeType
|
|
507
|
+
? `Dry run mode blocks ${probeType.replaceAll("-", " ")} command execution.`
|
|
508
|
+
: "Dry run mode blocks child process execution."),
|
|
509
|
+
kind: cdxgenActivity.kind || "execute",
|
|
510
|
+
metadata,
|
|
511
|
+
target: cdxgenActivity.target || target,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function getOutputByteSize(value, encoding = "utf-8") {
|
|
516
|
+
if (value === undefined || value === null) {
|
|
517
|
+
return 0;
|
|
518
|
+
}
|
|
519
|
+
if (Buffer.isBuffer(value)) {
|
|
520
|
+
return value.length;
|
|
521
|
+
}
|
|
522
|
+
if (ArrayBuffer.isView(value)) {
|
|
523
|
+
return value.byteLength;
|
|
524
|
+
}
|
|
525
|
+
const safeEncoding =
|
|
526
|
+
typeof encoding === "string" && encoding !== "buffer" ? encoding : "utf8";
|
|
527
|
+
return Buffer.byteLength(String(value), safeEncoding);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Safe wrapper around spawnSync that enforces permission checks, injects default
|
|
532
|
+
* options (maxBuffer, encoding, timeout), warns about unsafe Python and pip/uv
|
|
533
|
+
* invocations, and records every executed command in the commandsExecuted set.
|
|
534
|
+
*
|
|
535
|
+
* @param {string} command The executable to spawn
|
|
536
|
+
* @param {string[]} args Arguments to pass to the command
|
|
537
|
+
* @param {Object} options Options forwarded to spawnSync (e.g. cwd, env, shell)
|
|
538
|
+
* @returns {Object} spawnSync result object with status, stdout, stderr, and error fields
|
|
539
|
+
*/
|
|
540
|
+
export function safeSpawnSync(command, args, options) {
|
|
541
|
+
const activityDescriptor = buildCommandActivityDescriptor(
|
|
542
|
+
command,
|
|
543
|
+
args,
|
|
544
|
+
options,
|
|
545
|
+
);
|
|
546
|
+
const allowedCommandsEnv = readEnvironmentVariable("CDXGEN_ALLOWED_COMMANDS");
|
|
547
|
+
const commandAllowed = isAllowedCommand(command, allowedCommandsEnv);
|
|
548
|
+
if (allowedCommandsEnv) {
|
|
549
|
+
recordPolicyActivity(command, {
|
|
550
|
+
metadata: {
|
|
551
|
+
allowed: commandAllowed,
|
|
552
|
+
allowlist: allowedCommandsEnv,
|
|
553
|
+
policyType: "command-allowlist",
|
|
554
|
+
},
|
|
555
|
+
reason: `${commandAllowed ? "Allowed" : "Blocked"} command ${command} against CDXGEN_ALLOWED_COMMANDS.`,
|
|
556
|
+
status: commandAllowed ? "completed" : "blocked",
|
|
557
|
+
traceDetail: "allowlist",
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
if (isSecureMode && process.permission) {
|
|
561
|
+
const hasChildPermission = process.permission.has("child");
|
|
562
|
+
recordPolicyActivity(command, {
|
|
563
|
+
metadata: {
|
|
564
|
+
allowed: hasChildPermission,
|
|
565
|
+
policyType: "child-process",
|
|
566
|
+
},
|
|
567
|
+
reason: `${hasChildPermission ? "Confirmed" : "Denied"} child-process permission for ${command}.`,
|
|
568
|
+
status: hasChildPermission ? "completed" : "blocked",
|
|
569
|
+
traceDetail: "child-permission",
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
if (isDryRun) {
|
|
573
|
+
const error = createDryRunError(
|
|
574
|
+
"execute",
|
|
575
|
+
command,
|
|
576
|
+
activityDescriptor.blockedReason,
|
|
577
|
+
);
|
|
578
|
+
recordActivity({
|
|
579
|
+
kind: activityDescriptor.kind,
|
|
580
|
+
...activityDescriptor.metadata,
|
|
581
|
+
reason: error.message,
|
|
582
|
+
status: "blocked",
|
|
583
|
+
target: activityDescriptor.target,
|
|
584
|
+
});
|
|
585
|
+
return {
|
|
586
|
+
status: 1,
|
|
587
|
+
stdout: undefined,
|
|
588
|
+
stderr: undefined,
|
|
589
|
+
error,
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
if (
|
|
593
|
+
(isSecureMode && process.permission && !process.permission.has("child")) ||
|
|
594
|
+
!commandAllowed
|
|
595
|
+
) {
|
|
596
|
+
if (DEBUG_MODE) {
|
|
597
|
+
console.log(`cdxgen lacks execute permission for ${command}`);
|
|
598
|
+
}
|
|
599
|
+
recordActivity({
|
|
600
|
+
kind: activityDescriptor.kind,
|
|
601
|
+
...activityDescriptor.metadata,
|
|
602
|
+
reason: "cdxgen lacks execute permission for this command.",
|
|
603
|
+
status: "blocked",
|
|
604
|
+
target: activityDescriptor.target,
|
|
605
|
+
});
|
|
606
|
+
return {
|
|
607
|
+
status: 1,
|
|
608
|
+
stdout: undefined,
|
|
609
|
+
stderr: undefined,
|
|
610
|
+
error: new Error("No execute permission"),
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
if (isSecureMode) {
|
|
614
|
+
if (isWindowsShellHijackRisk(command, options)) {
|
|
615
|
+
const blockedReason = `${command} matches local file in cwd (Windows shell hijack risk)`;
|
|
616
|
+
console.warn(`\x1b[1;31mSecurity Alert: ${blockedReason}\x1b[0m`);
|
|
617
|
+
recordActivity({
|
|
618
|
+
kind: activityDescriptor.kind,
|
|
619
|
+
...activityDescriptor.metadata,
|
|
620
|
+
reason: blockedReason,
|
|
621
|
+
status: "blocked",
|
|
622
|
+
target: activityDescriptor.target,
|
|
623
|
+
});
|
|
624
|
+
return {
|
|
625
|
+
status: 1,
|
|
626
|
+
stdout: undefined,
|
|
627
|
+
stderr: undefined,
|
|
628
|
+
error: new Error(blockedReason),
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
if (options?.cwd && options.cwd !== resolve(options.cwd)) {
|
|
632
|
+
if (DEBUG_MODE) {
|
|
633
|
+
console.log(
|
|
634
|
+
"Executing commands with a relative cwd can cause security issues.",
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if (!options) {
|
|
640
|
+
options = {};
|
|
641
|
+
} else if (options.cdxgenActivity) {
|
|
642
|
+
options = {
|
|
643
|
+
...options,
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
if (options.cdxgenActivity) {
|
|
647
|
+
delete options.cdxgenActivity;
|
|
648
|
+
}
|
|
649
|
+
if (options.shell === true) {
|
|
650
|
+
const unsafeShellToken = getUnsafeShellToken(command, args);
|
|
651
|
+
if (unsafeShellToken !== undefined) {
|
|
652
|
+
const blockedReason = `Blocked shell execution for ${command}: command or argument contains shell metacharacters.`;
|
|
653
|
+
console.warn(`\x1b[1;31mSecurity Alert: ${blockedReason}\x1b[0m`);
|
|
654
|
+
recordActivity({
|
|
655
|
+
kind: activityDescriptor.kind,
|
|
656
|
+
...activityDescriptor.metadata,
|
|
657
|
+
reason: blockedReason,
|
|
658
|
+
status: "blocked",
|
|
659
|
+
target: activityDescriptor.target,
|
|
660
|
+
});
|
|
661
|
+
return {
|
|
662
|
+
status: 1,
|
|
663
|
+
stdout: undefined,
|
|
664
|
+
stderr: undefined,
|
|
665
|
+
error: new Error(blockedReason),
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
// Inject maxBuffer
|
|
670
|
+
if (!options.maxBuffer) {
|
|
671
|
+
options.maxBuffer = MAX_BUFFER;
|
|
672
|
+
}
|
|
673
|
+
// Inject encoding
|
|
674
|
+
if (!options.encoding) {
|
|
675
|
+
options.encoding = "utf-8";
|
|
676
|
+
}
|
|
677
|
+
// Inject timeout
|
|
678
|
+
if (!options.timeout) {
|
|
679
|
+
options.timeout = TIMEOUT_MS;
|
|
680
|
+
}
|
|
681
|
+
// Emit certain operational warnings only once per process to keep audit logs readable.
|
|
682
|
+
const emitNoticeOnce = (noticeKey, message, level = "warn") => {
|
|
683
|
+
if (!globalThis.__cdxgenNoticeCache) {
|
|
684
|
+
globalThis.__cdxgenNoticeCache = new Set();
|
|
685
|
+
}
|
|
686
|
+
if (globalThis.__cdxgenNoticeCache.has(noticeKey)) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
globalThis.__cdxgenNoticeCache.add(noticeKey);
|
|
690
|
+
if (level === "log") {
|
|
691
|
+
console.log(message);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
console.warn(message);
|
|
695
|
+
};
|
|
696
|
+
// Check for -S for python invocations in secure mode
|
|
697
|
+
if (command.includes("python") && (!args?.length || args[0] !== "-S")) {
|
|
698
|
+
if (isSecureMode) {
|
|
699
|
+
emitNoticeOnce(
|
|
700
|
+
"python-without-S-secure",
|
|
701
|
+
"\x1b[1;35mNotice: Running python command without '-S' argument. This is a bug in cdxgen. Please report with an example repo here https://github.com/cdxgen/cdxgen/issues.\x1b[0m",
|
|
702
|
+
);
|
|
703
|
+
} else if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") === "true") {
|
|
704
|
+
emitNoticeOnce(
|
|
705
|
+
"python-without-S-container",
|
|
706
|
+
"Running python command without '-S' argument.",
|
|
707
|
+
"log",
|
|
708
|
+
);
|
|
709
|
+
} else {
|
|
710
|
+
emitNoticeOnce(
|
|
711
|
+
"python-without-S-host",
|
|
712
|
+
"\x1b[1;35mNotice: Running python command without '-S' argument. Only run cdxgen in trusted directories to prevent auto-executing local scripts.\x1b[0m",
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
let isPyPackageInstall = false;
|
|
717
|
+
if (command.includes("pip") && args?.includes("install")) {
|
|
718
|
+
isPyPackageInstall = true;
|
|
719
|
+
} else if (
|
|
720
|
+
command.includes("python") &&
|
|
721
|
+
args?.includes("pip") &&
|
|
722
|
+
args?.includes("install")
|
|
723
|
+
) {
|
|
724
|
+
isPyPackageInstall = true;
|
|
725
|
+
} else if (
|
|
726
|
+
command.includes("uv") &&
|
|
727
|
+
args?.includes("pip") &&
|
|
728
|
+
args?.includes("install")
|
|
729
|
+
) {
|
|
730
|
+
isPyPackageInstall = true;
|
|
731
|
+
}
|
|
732
|
+
if (isPyPackageInstall) {
|
|
733
|
+
const hasOnlyBinary = args?.some(
|
|
734
|
+
(arg) => arg === "--only-binary" || arg.startsWith("--only-binary="),
|
|
735
|
+
);
|
|
736
|
+
if (!hasOnlyBinary) {
|
|
737
|
+
if (isSecureMode) {
|
|
738
|
+
emitNoticeOnce(
|
|
739
|
+
"pip-without-only-binary-secure",
|
|
740
|
+
"\x1b[1;31mSecurity Alert: pip/uv install invoked without '--only-binary' argument in secure mode. This is a bug in cdxgen and introduces Arbitrary Code Execution (ACE) risks. Please report with an example repo here https://github.com/cdxgen/cdxgen/issues.\x1b[0m",
|
|
741
|
+
);
|
|
742
|
+
} else if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") === "true") {
|
|
743
|
+
emitNoticeOnce(
|
|
744
|
+
"pip-without-only-binary-container",
|
|
745
|
+
"Running pip/uv install without '--only-binary' argument.",
|
|
746
|
+
"log",
|
|
747
|
+
);
|
|
748
|
+
} else {
|
|
749
|
+
emitNoticeOnce(
|
|
750
|
+
"pip-without-only-binary-host",
|
|
751
|
+
"\x1b[1;35mNotice: pip/uv install invoked without '--only-binary'. This allows executing untrusted setup.py scripts. Only run cdxgen in trusted directories.\x1b[0m",
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
traceLog("spawn", { command, args, ...options });
|
|
757
|
+
commandsExecuted.add(command);
|
|
758
|
+
// Fix for DEP0190 warning
|
|
759
|
+
if (options?.shell === true) {
|
|
760
|
+
if (args?.length) {
|
|
761
|
+
command = `${command} ${args.join(" ")}`;
|
|
762
|
+
args = undefined;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
const result = spawnSync(command, args, options);
|
|
766
|
+
recordActivity({
|
|
767
|
+
kind: activityDescriptor.kind,
|
|
768
|
+
...activityDescriptor.metadata,
|
|
769
|
+
stderrBytes: getOutputByteSize(result.stderr, options.encoding),
|
|
770
|
+
reason: result.error?.message,
|
|
771
|
+
status: result.status === 0 && !result.error ? "completed" : "failed",
|
|
772
|
+
stdoutBytes: getOutputByteSize(result.stdout, options.encoding),
|
|
773
|
+
target: activityDescriptor.target,
|
|
774
|
+
});
|
|
775
|
+
return result;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/** Default spawn timeout in milliseconds (20 minutes), overridable via CDXGEN_TIMEOUT_MS. */
|
|
779
|
+
export const TIMEOUT_MS =
|
|
780
|
+
Number.parseInt(readEnvironmentVariable("CDXGEN_TIMEOUT_MS"), 10) ||
|
|
781
|
+
20 * 60 * 1000;
|
|
782
|
+
|
|
783
|
+
/** Default maxBuffer size for spawned process stdout/stderr (100 MB), overridable via CDXGEN_MAX_BUFFER. */
|
|
784
|
+
export const MAX_BUFFER =
|
|
785
|
+
Number.parseInt(readEnvironmentVariable("CDXGEN_MAX_BUFFER"), 10) ||
|
|
786
|
+
100 * 1024 * 1024;
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Method to get files matching a pattern
|
|
790
|
+
*
|
|
791
|
+
* @param {string} dirPath Root directory for search
|
|
792
|
+
* @param {string} pattern Glob pattern (eg: *.gradle)
|
|
793
|
+
* @param {Object} options CLI options
|
|
794
|
+
*
|
|
795
|
+
* @returns {Array[string]} List of matched files
|
|
796
|
+
*/
|
|
797
|
+
export function getAllFiles(dirPath, pattern, options = {}) {
|
|
798
|
+
let ignoreList = [];
|
|
799
|
+
if (!options.noIgnore) {
|
|
800
|
+
ignoreList.push("**/.hg/**", "**/.git/**");
|
|
801
|
+
// Only ignore node_modules if the caller is not looking for package.json
|
|
802
|
+
if (!pattern.includes("package.json") && !options.includeNodeModulesDir) {
|
|
803
|
+
ignoreList.push("**/node_modules/**");
|
|
804
|
+
} else if (options.includeNodeModulesDir === false) {
|
|
805
|
+
ignoreList.push("**/node_modules/**");
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
if (options?.exclude && Array.isArray(options.exclude)) {
|
|
809
|
+
ignoreList = ignoreList.concat(options.exclude);
|
|
810
|
+
}
|
|
811
|
+
const includeDot =
|
|
812
|
+
options.includeDot ||
|
|
813
|
+
pattern.startsWith(".") ||
|
|
814
|
+
options.includeNodeModulesDir ||
|
|
815
|
+
options.noIgnore;
|
|
816
|
+
const defaultHits = getAllFilesWithIgnore(
|
|
817
|
+
dirPath,
|
|
818
|
+
pattern,
|
|
819
|
+
includeDot,
|
|
820
|
+
ignoreList,
|
|
821
|
+
);
|
|
822
|
+
// Support for specifying the pattern via options
|
|
823
|
+
if (options?.include?.length) {
|
|
824
|
+
const includeOnlyHits = getAllFilesWithIgnore(
|
|
825
|
+
dirPath,
|
|
826
|
+
options.include,
|
|
827
|
+
includeDot,
|
|
828
|
+
ignoreList,
|
|
829
|
+
);
|
|
830
|
+
if (!includeOnlyHits.length) {
|
|
831
|
+
return [];
|
|
832
|
+
}
|
|
833
|
+
return defaultHits.filter((f) => includeOnlyHits.includes(f));
|
|
834
|
+
}
|
|
835
|
+
return defaultHits;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Directory-walk caches, keyed by the root each walk starts from, and the one
|
|
840
|
+
* subtree they may be used for.
|
|
841
|
+
*
|
|
842
|
+
* A container scan enumerates the same rootfs path from about 25 ecosystem
|
|
843
|
+
* legs, each with a different glob pattern. `glob` reads the tree through a
|
|
844
|
+
* `PathScurry`, which memoises `readdir` and `lstat` per directory, so handing
|
|
845
|
+
* every call for a root the same instance turns those repeated walks into one
|
|
846
|
+
* walk followed by in-memory lookups. Pattern matching, ignore handling,
|
|
847
|
+
* ordering and dotfile rules all stay inside `glob`.
|
|
848
|
+
*
|
|
849
|
+
* Memoised directory entries describe the tree as it was first read, so they
|
|
850
|
+
* may only be reused where nothing changes during the scan. That holds for the
|
|
851
|
+
* exploded image layers, which are written once by the extractor and read from
|
|
852
|
+
* then on, and not for a source tree, where a build tool invoked by one
|
|
853
|
+
* ecosystem writes the lock file another goes on to look for. Caching is
|
|
854
|
+
* therefore confined to a subtree named by {@link setDirWalkCacheRoot}.
|
|
855
|
+
*
|
|
856
|
+
* A `PathScurry` is bound to the case sensitivity it was built with, so the
|
|
857
|
+
* cache holds one per root for the `nocase` walks issued from here.
|
|
858
|
+
*/
|
|
859
|
+
const dirWalkCache = new Map();
|
|
860
|
+
let dirWalkCacheRoot;
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* Confine directory-walk caching to one subtree, or switch it off.
|
|
864
|
+
*
|
|
865
|
+
* @param {string|undefined} rootDir Subtree whose contents are fixed for the rest of the scan
|
|
866
|
+
*/
|
|
867
|
+
export function setDirWalkCacheRoot(rootDir) {
|
|
868
|
+
if (rootDir !== dirWalkCacheRoot) {
|
|
869
|
+
dirWalkCache.clear();
|
|
870
|
+
}
|
|
871
|
+
dirWalkCacheRoot = rootDir || undefined;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Return the shared directory-walk cache for a root, creating it on first use.
|
|
876
|
+
*
|
|
877
|
+
* Constructing a `Glob` does not touch the filesystem; it is the supported way
|
|
878
|
+
* to obtain the `PathScurry` that `glob` would otherwise build per call.
|
|
879
|
+
*
|
|
880
|
+
* @param {string} dirPath Root directory the walk starts from
|
|
881
|
+
* @returns {object|undefined} Cache to pass to `globSync`, or undefined when the path is not cacheable
|
|
882
|
+
*/
|
|
883
|
+
function getDirWalkCache(dirPath) {
|
|
884
|
+
if (!(dirWalkCacheRoot && dirPath?.startsWith(dirWalkCacheRoot))) {
|
|
885
|
+
return undefined;
|
|
886
|
+
}
|
|
887
|
+
if (dirWalkCache.has(dirPath)) {
|
|
888
|
+
return dirWalkCache.get(dirPath);
|
|
889
|
+
}
|
|
890
|
+
let scurry;
|
|
891
|
+
try {
|
|
892
|
+
scurry = new Glob("**/*", { cwd: dirPath, nocase: true }).scurry;
|
|
893
|
+
} catch (_err) {
|
|
894
|
+
scurry = undefined;
|
|
895
|
+
}
|
|
896
|
+
dirWalkCache.set(dirPath, scurry);
|
|
897
|
+
return scurry;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Release every cached directory walk.
|
|
902
|
+
*
|
|
903
|
+
* Called when a BOM generation cycle starts, so that a long-lived process such
|
|
904
|
+
* as the server never serves a scan from an earlier scan's view of the
|
|
905
|
+
* filesystem, and so the retained directory entries are freed.
|
|
906
|
+
*/
|
|
907
|
+
export function clearFileDiscoveryCache() {
|
|
908
|
+
dirWalkCache.clear();
|
|
909
|
+
dirWalkCacheRoot = undefined;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Method to get files matching a pattern
|
|
914
|
+
*
|
|
915
|
+
* @param {string} dirPath Root directory for search
|
|
916
|
+
* @param {string} pattern Glob pattern (eg: *.gradle)
|
|
917
|
+
* @param {Boolean} includeDot whether hidden files can be included.
|
|
918
|
+
* @param {Array} ignoreList Directory patterns to ignore
|
|
919
|
+
*
|
|
920
|
+
* @returns {Array[string]} List of matched files
|
|
921
|
+
*/
|
|
922
|
+
export function getAllFilesWithIgnore(
|
|
923
|
+
dirPath,
|
|
924
|
+
pattern,
|
|
925
|
+
includeDot,
|
|
926
|
+
ignoreList,
|
|
927
|
+
) {
|
|
928
|
+
const patternValue = Array.isArray(pattern)
|
|
929
|
+
? pattern.join(",")
|
|
930
|
+
: String(pattern);
|
|
931
|
+
const discoveryMetadata = classifyDiscoveryPattern(patternValue);
|
|
932
|
+
try {
|
|
933
|
+
const files = globSync(pattern, {
|
|
934
|
+
cwd: dirPath,
|
|
935
|
+
absolute: true,
|
|
936
|
+
nocase: true,
|
|
937
|
+
nodir: true,
|
|
938
|
+
dot: includeDot,
|
|
939
|
+
follow: false,
|
|
940
|
+
ignore: ignoreList,
|
|
941
|
+
scurry: getDirWalkCache(dirPath),
|
|
942
|
+
});
|
|
943
|
+
recordDiscoveryActivity(`${dirPath} :: ${patternValue}`, {
|
|
944
|
+
metadata: {
|
|
945
|
+
discoveryType: discoveryMetadata.discoveryType,
|
|
946
|
+
matchedCount: files.length,
|
|
947
|
+
pattern: patternValue,
|
|
948
|
+
},
|
|
949
|
+
traceDetail: `matched:${files.length}`,
|
|
950
|
+
reasonBuilder: (count) =>
|
|
951
|
+
`Scanned ${dirPath} with glob '${patternValue}' for ${discoveryMetadata.label}; matched ${files.length} path(s)${buildReadCountSuffix(count)}.`,
|
|
952
|
+
});
|
|
953
|
+
recordSuspiciousShellPathActivities(files, {
|
|
954
|
+
discoveryType: discoveryMetadata.discoveryType,
|
|
955
|
+
pattern: patternValue,
|
|
956
|
+
});
|
|
957
|
+
if (files.length > 1) {
|
|
958
|
+
thoughtLog(
|
|
959
|
+
`Found ${files.length} files for the pattern '${pattern}' at '${dirPath}'.`,
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
return files;
|
|
963
|
+
} catch (err) {
|
|
964
|
+
recordDiscoveryActivity(`${dirPath} :: ${patternValue}`, {
|
|
965
|
+
metadata: {
|
|
966
|
+
discoveryType: discoveryMetadata.discoveryType,
|
|
967
|
+
pattern: patternValue,
|
|
968
|
+
},
|
|
969
|
+
reason: `File discovery failed for glob '${patternValue}' under ${dirPath}: ${err.message}`,
|
|
970
|
+
status: "failed",
|
|
971
|
+
});
|
|
972
|
+
if (DEBUG_MODE) {
|
|
973
|
+
console.error(err);
|
|
974
|
+
}
|
|
975
|
+
return [];
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* Return the current timestamp in YYYY-MM-DDTHH:MM:SSZ format.
|
|
981
|
+
*
|
|
982
|
+
* @returns {string} ISO formatted timestamp, without milliseconds.
|
|
983
|
+
*/
|
|
984
|
+
export function getTimestamp() {
|
|
985
|
+
return `${new Date().toISOString().split(".")[0]}Z`;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* Return the temp directory, creating CDXGEN_TEMP_DIR when it is set but does
|
|
990
|
+
* not yet exist. Falls back to the OS tmpdir when unset.
|
|
991
|
+
*
|
|
992
|
+
* @returns {string} Resolved temp directory path.
|
|
993
|
+
*/
|
|
994
|
+
export function getTmpDir() {
|
|
995
|
+
if (
|
|
996
|
+
readEnvironmentVariable("CDXGEN_TEMP_DIR") &&
|
|
997
|
+
!safeExistsSync(readEnvironmentVariable("CDXGEN_TEMP_DIR"))
|
|
998
|
+
) {
|
|
999
|
+
safeMkdirSync(readEnvironmentVariable("CDXGEN_TEMP_DIR"), {
|
|
1000
|
+
recursive: true,
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
return readEnvironmentVariable("CDXGEN_TEMP_DIR") || tmpdir();
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Computes the checksum for a file path using the given hash algorithm
|
|
1008
|
+
*
|
|
1009
|
+
* @param {string} hashName name of hash algorithm
|
|
1010
|
+
* @param {string} path path to file
|
|
1011
|
+
* @returns {Promise<String>} hex value of hash
|
|
1012
|
+
*/
|
|
1013
|
+
export function checksumFile(hashName, path) {
|
|
1014
|
+
return new Promise((resolve, reject) => {
|
|
1015
|
+
const hash = createHash(hashName);
|
|
1016
|
+
const stream = createReadStream(path);
|
|
1017
|
+
stream.on("error", (err) => reject(err));
|
|
1018
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
1019
|
+
stream.on("end", () => resolve(hash.digest("hex")));
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* Computes multiple checksum for a file path using the given hash algorithms
|
|
1025
|
+
*
|
|
1026
|
+
* @param {Array[String]} algorithms Array of algorithms
|
|
1027
|
+
* @param {string} path path to file
|
|
1028
|
+
* @returns {Promise<Object>} hashes object
|
|
1029
|
+
*/
|
|
1030
|
+
export function multiChecksumFile(algorithms, path) {
|
|
1031
|
+
return new Promise((resolve, reject) => {
|
|
1032
|
+
const hashes = {};
|
|
1033
|
+
for (const alg of algorithms) {
|
|
1034
|
+
hashes[alg] = createHash(alg);
|
|
1035
|
+
}
|
|
1036
|
+
const stream = createReadStream(path);
|
|
1037
|
+
let errorOccurred = false;
|
|
1038
|
+
stream.on("error", (err) => {
|
|
1039
|
+
errorOccurred = true;
|
|
1040
|
+
reject(err);
|
|
1041
|
+
});
|
|
1042
|
+
stream.on("data", (chunk) =>
|
|
1043
|
+
algorithms.forEach((alg) => {
|
|
1044
|
+
hashes[alg].update(chunk);
|
|
1045
|
+
}),
|
|
1046
|
+
);
|
|
1047
|
+
stream.on("end", () => {
|
|
1048
|
+
algorithms.forEach((alg) => {
|
|
1049
|
+
hashes[alg] = hashes[alg].digest("hex");
|
|
1050
|
+
});
|
|
1051
|
+
});
|
|
1052
|
+
stream.on("close", () => {
|
|
1053
|
+
if (!errorOccurred) {
|
|
1054
|
+
resolve(hashes);
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
});
|
|
1058
|
+
}
|