@cdxgen/cdxgen 0.0.1 → 13.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +921 -87
- package/bin/audit.js +239 -0
- package/bin/cdxgen.js +2335 -0
- package/bin/convert.js +220 -0
- package/bin/evinse.js +353 -0
- package/bin/hbom.js +504 -0
- package/bin/repl.js +2224 -0
- package/bin/sign.js +195 -0
- package/bin/tracebom.js +303 -0
- package/bin/validate.js +268 -0
- package/bin/verify.js +189 -0
- package/data/README.md +307 -0
- package/data/bom-1.4.schema.json +1605 -0
- package/data/bom-1.5.schema.json +3660 -0
- package/data/bom-1.6.schema.json +5511 -0
- package/data/bom-1.7.schema.json +6700 -0
- package/data/cbomosdb-queries.json +68 -0
- package/data/component-tags.json +339 -0
- package/data/container-knowledge-index.json +125 -0
- package/data/cosdb-queries.json +17 -0
- package/data/crypto-oid.json +1998 -0
- package/data/cryptography-defs.json +3793 -0
- package/data/cryptography-defs.schema.json +576 -0
- package/data/cyclonedx-2.0-bundled.schema.json +7182 -0
- package/data/frameworks-list.json +219 -0
- package/data/glibc-stdlib.json +117 -0
- package/data/gtfobins-index.json +6296 -0
- package/data/helpers/init.gradle +71 -0
- package/data/jsf-0.82.schema.json +211 -0
- package/data/known-licenses.json +82 -0
- package/data/lic-mapping.json +338 -0
- package/data/license-aliases.json +6624 -0
- package/data/license-db.json +39059 -0
- package/data/license-deprecations.json +302 -0
- package/data/lolbas-index.json +150 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/pypi-pkg-aliases.json +1199 -0
- package/data/python-stdlib.json +308 -0
- package/data/queries-darwin.json +193 -0
- package/data/queries-win.json +257 -0
- package/data/queries.json +268 -0
- package/data/ruby-known-modules.json +281 -0
- package/data/rules/ai-agent-governance.yaml +323 -0
- package/data/rules/ai-bom.yaml +268 -0
- package/data/rules/ai-oversight.yaml +186 -0
- package/data/rules/ai-provenance.yaml +92 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/cbom-security.yaml +165 -0
- package/data/rules/chrome-extensions.yaml +248 -0
- package/data/rules/ci-permissions.yaml +802 -0
- package/data/rules/container-risk.yaml +353 -0
- package/data/rules/dependency-sources.yaml +236 -0
- package/data/rules/golem-go.yaml +229 -0
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +388 -0
- package/data/rules/obom-runtime.yaml +1776 -0
- package/data/rules/package-integrity.yaml +364 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +237 -0
- package/data/spdx-export.schema.json +6794 -0
- package/data/spdx-license-list.json +7449 -0
- package/data/spdx-licenses.json +759 -0
- package/data/spdx.schema.json +819 -0
- package/data/templates/README.md +3 -0
- package/data/templates/asvs-4.0.3.cdx.json +2943 -0
- package/data/templates/asvs-5.0.cdx.json +3046 -0
- package/data/templates/bsimm-v13.cdx.json +1008 -0
- package/data/templates/masvs-2.0.0.cdx.json +225 -0
- package/data/templates/nist-ssdf-1.1.cdx.json +828 -0
- package/data/templates/pcissc-secure-slc-1.1.cdx.json +1027 -0
- package/data/templates/scvs-1.0.0.cdx.json +813 -0
- package/data/templates/ssaf-DRAFT-2023-11.cdx.json +127 -0
- package/data/vendor-alias.json +41967 -0
- package/data/wrapdb-releases.json +4227 -0
- package/index.cjs +15 -0
- package/lib/audit/index.js +2800 -0
- package/lib/audit/progress.js +114 -0
- package/lib/audit/reporters.js +937 -0
- package/lib/audit/scoring.js +560 -0
- package/lib/audit/targets.js +798 -0
- package/lib/cli/bomAssembly.js +1882 -0
- package/lib/cli/cliOptions.js +543 -0
- package/lib/cli/index.js +2759 -0
- package/lib/cli/jsBom.js +2087 -0
- package/lib/cli/jvmBom.js +1858 -0
- package/lib/cli/managedBom.js +2083 -0
- package/lib/cli/nativeBom.js +2125 -0
- package/lib/core/activity.js +1087 -0
- package/lib/core/env.js +719 -0
- package/lib/core/fs.js +1058 -0
- package/lib/core/httpClient.js +730 -0
- package/lib/core/logger.js +280 -0
- package/lib/core/parallel.js +323 -0
- package/lib/core/paths.js +70 -0
- package/lib/core/projectConfig.js +122 -0
- package/lib/core/propertySanitizer.js +174 -0
- package/lib/core/spdx.js +5 -0
- package/lib/core/state.js +59 -0
- package/lib/core/text.js +207 -0
- package/lib/core/ui.js +920 -0
- package/lib/core/urls.js +84 -0
- package/lib/ecosystems/asarutils.js +1636 -0
- package/lib/ecosystems/bunutils.js +402 -0
- package/lib/ecosystems/caxa.js +77 -0
- package/lib/ecosystems/chromextutils.js +1174 -0
- package/lib/ecosystems/cmakeResolver.js +587 -0
- package/lib/ecosystems/cppEvidence.js +305 -0
- package/lib/ecosystems/denoutils.js +1094 -0
- package/lib/ecosystems/dotnetutils.js +132 -0
- package/lib/ecosystems/ecosystems.js +2772 -0
- package/lib/ecosystems/golem.js +1807 -0
- package/lib/ecosystems/gradleutils.js +1048 -0
- package/lib/ecosystems/jsEvidence.js +317 -0
- package/lib/ecosystems/npmutils.js +586 -0
- package/lib/ecosystems/parsers-bazel.js +875 -0
- package/lib/ecosystems/parsers-dotnet.js +1430 -0
- package/lib/ecosystems/parsers-gleam.js +302 -0
- package/lib/ecosystems/parsers-go.js +818 -0
- package/lib/ecosystems/parsers-js.js +4222 -0
- package/lib/ecosystems/parsers-jvm.js +948 -0
- package/lib/ecosystems/parsers-misc.js +3191 -0
- package/lib/ecosystems/parsers-python.js +2070 -0
- package/lib/ecosystems/parsers-rust.js +1294 -0
- package/lib/ecosystems/parsers-zig.js +861 -0
- package/lib/ecosystems/pep770.js +341 -0
- package/lib/ecosystems/pylockutils.js +427 -0
- package/lib/ecosystems/pythonutils.js +1281 -0
- package/lib/ecosystems/registryProvenance.js +1003 -0
- package/lib/ecosystems/remote/huggingface.js +1343 -0
- package/lib/ecosystems/rubyutils.js +1629 -0
- package/lib/ecosystems/rusi.js +820 -0
- package/lib/ecosystems/sbtutils.js +972 -0
- package/lib/ecosystems/tea.js +607 -0
- package/lib/ecosystems/utils.js +583 -0
- package/lib/ecosystems/zigResolver.js +410 -0
- package/lib/evinser/db.js +145 -0
- package/lib/evinser/evinser.js +2362 -0
- package/lib/evinser/scalasem.js +65 -0
- package/lib/evinser/swiftsem.js +767 -0
- package/lib/helpers/annotationFormatter.js +84 -0
- package/lib/helpers/bomSigner.js +312 -0
- package/lib/helpers/exportUtils.js +160 -0
- package/lib/helpers/remote/dependency-track.js +117 -0
- package/lib/helpers/versutils.js +202 -0
- package/lib/helpers/vsixutils.js +1069 -0
- package/lib/inventory/agentFormulationParser.js +322 -0
- package/lib/inventory/aiCollector.js +2140 -0
- package/lib/inventory/aiInventory.js +414 -0
- package/lib/inventory/aiModelVariants.js +121 -0
- package/lib/inventory/aiOversightCollector.js +661 -0
- package/lib/inventory/aiProvenanceCollector.js +822 -0
- package/lib/inventory/analyzer.js +6089 -0
- package/lib/inventory/analyzerScope.js +807 -0
- package/lib/inventory/astWorker.js +20 -0
- package/lib/inventory/atomUtils.js +1092 -0
- package/lib/inventory/auditCategories.js +192 -0
- package/lib/inventory/bomUtils.js +369 -0
- package/lib/inventory/cacheCommands.js +182 -0
- package/lib/inventory/cacheDir.js +104 -0
- package/lib/inventory/cbomutils.js +590 -0
- package/lib/inventory/cdxrs.js +434 -0
- package/lib/inventory/ciParsers/azurePipelines.js +295 -0
- package/lib/inventory/ciParsers/circleCi.js +286 -0
- package/lib/inventory/ciParsers/common.js +24 -0
- package/lib/inventory/ciParsers/githubActions.js +2434 -0
- package/lib/inventory/ciParsers/gitlabCi.js +213 -0
- package/lib/inventory/ciParsers/jenkins.js +180 -0
- package/lib/inventory/citations.js +234 -0
- package/lib/inventory/communityAiConfigParser.js +756 -0
- package/lib/inventory/containerRisk.js +204 -0
- package/lib/inventory/cryptoAlgorithmFamily.js +258 -0
- package/lib/inventory/deps.js +807 -0
- package/lib/inventory/depsUtils.js +588 -0
- package/lib/inventory/display.js +2128 -0
- package/lib/inventory/dosai.js +601 -0
- package/lib/inventory/dosaiParsers.js +154 -0
- package/lib/inventory/dynamic.js +145 -0
- package/lib/inventory/envcontext.js +1793 -0
- package/lib/inventory/evidenceUtils.js +774 -0
- package/lib/inventory/fetchBatch.js +779 -0
- package/lib/inventory/fetchRate.js +255 -0
- package/lib/inventory/forgeEnricher.js +300 -0
- package/lib/inventory/formulationParsers.js +422 -0
- package/lib/inventory/gtfobins.js +339 -0
- package/lib/inventory/hbom.js +719 -0
- package/lib/inventory/hbomAnalysis.js +310 -0
- package/lib/inventory/hbomLoader.js +35 -0
- package/lib/inventory/hostTopology.js +835 -0
- package/lib/inventory/inventoryStats.js +100 -0
- package/lib/inventory/jsonLike.js +121 -0
- package/lib/inventory/licenseEnhancer.js +918 -0
- package/lib/inventory/lolbas.js +285 -0
- package/lib/inventory/mcp.js +253 -0
- package/lib/inventory/mcpConfigParser.js +683 -0
- package/lib/inventory/mcpDiscovery.js +112 -0
- package/lib/inventory/mcpPinning.js +209 -0
- package/lib/inventory/osPackageResolver.js +493 -0
- package/lib/inventory/osinfo.js +383 -0
- package/lib/inventory/osqueryTransform.js +274 -0
- package/lib/inventory/plugins.js +466 -0
- package/lib/inventory/protobom.js +231 -0
- package/lib/inventory/protobomLoader.js +43 -0
- package/lib/inventory/provenanceUtils.js +224 -0
- package/lib/inventory/purl.js +749 -0
- package/lib/inventory/rustFormulationParser.js +339 -0
- package/lib/inventory/sbomDocument.js +340 -0
- package/lib/inventory/source.js +1488 -0
- package/lib/inventory/spdx.js +361 -0
- package/lib/inventory/spdxExpression.js +512 -0
- package/lib/inventory/spdxUtils.js +107 -0
- package/lib/inventory/table.js +267 -0
- package/lib/inventory/traceRunner.js +439 -0
- package/lib/inventory/unicodeScan.js +147 -0
- package/lib/managers/binary.js +3459 -0
- package/lib/managers/containerutils.js +125 -0
- package/lib/managers/docker.js +2145 -0
- package/lib/managers/dockerConnection.js +162 -0
- package/lib/managers/oci.js +704 -0
- package/lib/managers/piptree.js +267 -0
- package/lib/parsers/cmakeCache.js +199 -0
- package/lib/parsers/gguf.js +492 -0
- package/lib/parsers/gitAiNotes.js +233 -0
- package/lib/parsers/gitmodules.js +239 -0
- package/lib/parsers/htmlExtract.js +610 -0
- package/lib/parsers/huggingfaceManifest.js +551 -0
- package/lib/parsers/huggingfaceUtils.js +506 -0
- package/lib/parsers/iri.js +618 -0
- package/lib/parsers/npmrc.js +99 -0
- package/lib/parsers/ollama.js +101 -0
- package/lib/parsers/xml.js +841 -0
- package/lib/server/openapi.yaml +433 -0
- package/lib/server/server.js +616 -0
- package/lib/stages/postgen/annotator.js +977 -0
- package/lib/stages/postgen/auditBom.js +468 -0
- package/lib/stages/postgen/postgen.js +1239 -0
- package/lib/stages/postgen/ruleEngine.js +731 -0
- package/lib/stages/postgen/sortBom.js +195 -0
- package/lib/stages/postgen/spdxConverter.js +796 -0
- package/lib/stages/postgen/specVersionCompat.js +703 -0
- package/lib/stages/pregen/envAudit.js +388 -0
- package/lib/stages/pregen/pregen.js +637 -0
- package/lib/third-party/README.md +9 -0
- package/lib/third-party/arborist/CHANGELOG.md +1109 -0
- package/lib/third-party/arborist/LICENSE.md +20 -0
- package/lib/third-party/arborist/README.md +315 -0
- package/lib/third-party/arborist/lib/arborist/index.js +258 -0
- package/lib/third-party/arborist/lib/arborist/load-actual.js +605 -0
- package/lib/third-party/arborist/lib/arborist/load-virtual.js +300 -0
- package/lib/third-party/arborist/lib/bin-links.js +120 -0
- package/lib/third-party/arborist/lib/calc-dep-flags.js +130 -0
- package/lib/third-party/arborist/lib/case-insensitive-map.js +51 -0
- package/lib/third-party/arborist/lib/consistent-resolve.js +42 -0
- package/lib/third-party/arborist/lib/debug.js +50 -0
- package/lib/third-party/arborist/lib/dep-valid.js +190 -0
- package/lib/third-party/arborist/lib/edge.js +417 -0
- package/lib/third-party/arborist/lib/from-path.js +36 -0
- package/lib/third-party/arborist/lib/gather-dep-set.js +43 -0
- package/lib/third-party/arborist/lib/index.js +22 -0
- package/lib/third-party/arborist/lib/inventory.js +138 -0
- package/lib/third-party/arborist/lib/link.js +169 -0
- package/lib/third-party/arborist/lib/node.js +1673 -0
- package/lib/third-party/arborist/lib/npm-extension.js +45 -0
- package/lib/third-party/arborist/lib/override-resolves.js +11 -0
- package/lib/third-party/arborist/lib/override-set.js +319 -0
- package/lib/third-party/arborist/lib/package-extensions.js +289 -0
- package/lib/third-party/arborist/lib/printable.js +210 -0
- package/lib/third-party/arborist/lib/proc-log.js +30 -0
- package/lib/third-party/arborist/lib/realpath.js +100 -0
- package/lib/third-party/arborist/lib/relpath.js +4 -0
- package/lib/third-party/arborist/lib/shrinkwrap.js +1291 -0
- package/lib/third-party/arborist/lib/spec-from-lock.js +34 -0
- package/lib/third-party/arborist/lib/tree-check.js +165 -0
- package/lib/third-party/arborist/lib/validate-npm-package-name.js +107 -0
- package/lib/third-party/arborist/lib/version-from-tgz.js +51 -0
- package/lib/third-party/arborist/lib/yarn-lock.js +397 -0
- package/lib/validator/bomValidator.js +985 -0
- package/lib/validator/complianceEngine.js +241 -0
- package/lib/validator/complianceRules.js +1680 -0
- package/lib/validator/generated/runtime.mjs +17 -0
- package/lib/validator/generated/validate-1.6.mjs +21258 -0
- package/lib/validator/generated/validate-1.7.mjs +24803 -0
- package/lib/validator/generated/validate-2.0.mjs +22931 -0
- package/lib/validator/index.js +246 -0
- package/lib/validator/reporters/annotations.js +142 -0
- package/lib/validator/reporters/console.js +160 -0
- package/lib/validator/reporters/index.js +41 -0
- package/lib/validator/reporters/json.js +37 -0
- package/lib/validator/reporters/sarif.js +184 -0
- package/package.json +209 -26
- package/types/bin/audit.d.ts +3 -0
- package/types/bin/audit.d.ts.map +1 -0
- package/types/bin/cdxgen.d.ts +3 -0
- package/types/bin/cdxgen.d.ts.map +1 -0
- package/types/bin/convert.d.ts +3 -0
- package/types/bin/convert.d.ts.map +1 -0
- package/types/bin/evinse.d.ts +3 -0
- package/types/bin/evinse.d.ts.map +1 -0
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts +3 -0
- package/types/bin/repl.d.ts.map +1 -0
- package/types/bin/sign.d.ts +3 -0
- package/types/bin/sign.d.ts.map +1 -0
- package/types/bin/tracebom.d.ts +3 -0
- package/types/bin/tracebom.d.ts.map +1 -0
- package/types/bin/validate.d.ts +14 -0
- package/types/bin/validate.d.ts.map +1 -0
- package/types/bin/verify.d.ts +3 -0
- package/types/bin/verify.d.ts.map +1 -0
- package/types/lib/audit/index.d.ts +153 -0
- package/types/lib/audit/index.d.ts.map +1 -0
- package/types/lib/audit/progress.d.ts +31 -0
- package/types/lib/audit/progress.d.ts.map +1 -0
- package/types/lib/audit/reporters.d.ts +62 -0
- package/types/lib/audit/reporters.d.ts.map +1 -0
- package/types/lib/audit/scoring.d.ts +36 -0
- package/types/lib/audit/scoring.d.ts.map +1 -0
- package/types/lib/audit/targets.d.ts +77 -0
- package/types/lib/audit/targets.d.ts.map +1 -0
- package/types/lib/cli/bomAssembly.d.ts +329 -0
- package/types/lib/cli/bomAssembly.d.ts.map +1 -0
- package/types/lib/cli/cliOptions.d.ts +156 -0
- package/types/lib/cli/cliOptions.d.ts.map +1 -0
- package/types/lib/cli/index.d.ts +107 -0
- package/types/lib/cli/index.d.ts.map +1 -0
- package/types/lib/cli/jsBom.d.ts +94 -0
- package/types/lib/cli/jsBom.d.ts.map +1 -0
- package/types/lib/cli/jvmBom.d.ts +54 -0
- package/types/lib/cli/jvmBom.d.ts.map +1 -0
- package/types/lib/cli/managedBom.d.ts +105 -0
- package/types/lib/cli/managedBom.d.ts.map +1 -0
- package/types/lib/cli/nativeBom.d.ts +143 -0
- package/types/lib/cli/nativeBom.d.ts.map +1 -0
- package/types/lib/core/activity.d.ts +178 -0
- package/types/lib/core/activity.d.ts.map +1 -0
- package/types/lib/core/env.d.ts +192 -0
- package/types/lib/core/env.d.ts.map +1 -0
- package/types/lib/core/fs.d.ts +158 -0
- package/types/lib/core/fs.d.ts.map +1 -0
- package/types/lib/core/httpClient.d.ts +149 -0
- package/types/lib/core/httpClient.d.ts.map +1 -0
- package/types/lib/core/logger.d.ts +50 -0
- package/types/lib/core/logger.d.ts.map +1 -0
- package/types/lib/core/parallel.d.ts +95 -0
- package/types/lib/core/parallel.d.ts.map +1 -0
- package/types/lib/core/paths.d.ts +36 -0
- package/types/lib/core/paths.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts +23 -0
- package/types/lib/core/projectConfig.d.ts.map +1 -0
- package/types/lib/core/propertySanitizer.d.ts +23 -0
- package/types/lib/core/propertySanitizer.d.ts.map +1 -0
- package/types/lib/core/spdx.d.ts +5 -0
- package/types/lib/core/spdx.d.ts.map +1 -0
- package/types/lib/core/state.d.ts +20 -0
- package/types/lib/core/state.d.ts.map +1 -0
- package/types/lib/core/text.d.ts +78 -0
- package/types/lib/core/text.d.ts.map +1 -0
- package/types/lib/core/ui.d.ts +87 -0
- package/types/lib/core/ui.d.ts.map +1 -0
- package/types/lib/core/urls.d.ts +43 -0
- package/types/lib/core/urls.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts +71 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -0
- package/types/lib/ecosystems/bunutils.d.ts +38 -0
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -0
- package/types/lib/ecosystems/caxa.d.ts +8 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -0
- package/types/lib/ecosystems/chromextutils.d.ts +97 -0
- package/types/lib/ecosystems/chromextutils.d.ts.map +1 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts +176 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +35 -0
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +76 -0
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -0
- package/types/lib/ecosystems/dotnetutils.d.ts +45 -0
- package/types/lib/ecosystems/dotnetutils.d.ts.map +1 -0
- package/types/lib/ecosystems/ecosystems.d.ts +279 -0
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -0
- package/types/lib/ecosystems/golem.d.ts +60 -0
- package/types/lib/ecosystems/golem.d.ts.map +1 -0
- package/types/lib/ecosystems/gradleutils.d.ts +139 -0
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -0
- package/types/lib/ecosystems/jsEvidence.d.ts +17 -0
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -0
- package/types/lib/ecosystems/npmutils.d.ts +183 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts +36 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts +116 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-gleam.d.ts +33 -0
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-go.d.ts +92 -0
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-js.d.ts +242 -0
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-jvm.d.ts +100 -0
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-misc.d.ts +450 -0
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-python.d.ts +145 -0
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rust.d.ts +56 -0
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-zig.d.ts +83 -0
- package/types/lib/ecosystems/parsers-zig.d.ts.map +1 -0
- package/types/lib/ecosystems/pep770.d.ts +38 -0
- package/types/lib/ecosystems/pep770.d.ts.map +1 -0
- package/types/lib/ecosystems/pylockutils.d.ts +68 -0
- package/types/lib/ecosystems/pylockutils.d.ts.map +1 -0
- package/types/lib/ecosystems/pythonutils.d.ts +70 -0
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -0
- package/types/lib/ecosystems/registryProvenance.d.ts +26 -0
- package/types/lib/ecosystems/registryProvenance.d.ts.map +1 -0
- package/types/lib/ecosystems/remote/huggingface.d.ts +31 -0
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -0
- package/types/lib/ecosystems/rubyutils.d.ts +182 -0
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -0
- package/types/lib/ecosystems/rusi.d.ts +40 -0
- package/types/lib/ecosystems/rusi.d.ts.map +1 -0
- package/types/lib/ecosystems/sbtutils.d.ts +179 -0
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -0
- package/types/lib/ecosystems/tea.d.ts +180 -0
- package/types/lib/ecosystems/tea.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +41 -0
- package/types/lib/ecosystems/utils.d.ts.map +1 -0
- package/types/lib/ecosystems/zigResolver.d.ts +70 -0
- package/types/lib/ecosystems/zigResolver.d.ts.map +1 -0
- package/types/lib/evinser/db.d.ts +17 -0
- package/types/lib/evinser/db.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +354 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -0
- package/types/lib/evinser/scalasem.d.ts +15 -0
- package/types/lib/evinser/scalasem.d.ts.map +1 -0
- package/types/lib/evinser/swiftsem.d.ts +103 -0
- package/types/lib/evinser/swiftsem.d.ts.map +1 -0
- package/types/lib/helpers/annotationFormatter.d.ts +23 -0
- package/types/lib/helpers/annotationFormatter.d.ts.map +1 -0
- package/types/lib/helpers/bomSigner.d.ts +28 -0
- package/types/lib/helpers/bomSigner.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts +52 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -0
- package/types/lib/helpers/remote/dependency-track.d.ts +23 -0
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
- package/types/lib/helpers/versutils.d.ts +8 -0
- package/types/lib/helpers/versutils.d.ts.map +1 -0
- package/types/lib/helpers/vsixutils.d.ts +130 -0
- package/types/lib/helpers/vsixutils.d.ts.map +1 -0
- package/types/lib/inventory/agentFormulationParser.d.ts +21 -0
- package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -0
- package/types/lib/inventory/aiCollector.d.ts +61 -0
- package/types/lib/inventory/aiCollector.d.ts.map +1 -0
- package/types/lib/inventory/aiInventory.d.ts +103 -0
- package/types/lib/inventory/aiInventory.d.ts.map +1 -0
- package/types/lib/inventory/aiModelVariants.d.ts +31 -0
- package/types/lib/inventory/aiModelVariants.d.ts.map +1 -0
- package/types/lib/inventory/aiOversightCollector.d.ts +28 -0
- package/types/lib/inventory/aiOversightCollector.d.ts.map +1 -0
- package/types/lib/inventory/aiProvenanceCollector.d.ts +13 -0
- package/types/lib/inventory/aiProvenanceCollector.d.ts.map +1 -0
- package/types/lib/inventory/analyzer.d.ts +157 -0
- package/types/lib/inventory/analyzer.d.ts.map +1 -0
- package/types/lib/inventory/analyzerScope.d.ts +106 -0
- package/types/lib/inventory/analyzerScope.d.ts.map +1 -0
- package/types/lib/inventory/astWorker.d.ts +9 -0
- package/types/lib/inventory/astWorker.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +159 -0
- package/types/lib/inventory/atomUtils.d.ts.map +1 -0
- package/types/lib/inventory/auditCategories.d.ts +80 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -0
- package/types/lib/inventory/bomUtils.d.ts +145 -0
- package/types/lib/inventory/bomUtils.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +28 -0
- package/types/lib/inventory/cacheCommands.d.ts.map +1 -0
- package/types/lib/inventory/cacheDir.d.ts +55 -0
- package/types/lib/inventory/cacheDir.d.ts.map +1 -0
- package/types/lib/inventory/cbomutils.d.ts +37 -0
- package/types/lib/inventory/cbomutils.d.ts.map +1 -0
- package/types/lib/inventory/cdxrs.d.ts +90 -0
- package/types/lib/inventory/cdxrs.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/azurePipelines.d.ts +27 -0
- package/types/lib/inventory/ciParsers/azurePipelines.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/circleCi.d.ts +27 -0
- package/types/lib/inventory/ciParsers/circleCi.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/common.d.ts +11 -0
- package/types/lib/inventory/ciParsers/common.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/githubActions.d.ts +38 -0
- package/types/lib/inventory/ciParsers/githubActions.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/gitlabCi.d.ts +26 -0
- package/types/lib/inventory/ciParsers/gitlabCi.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/jenkins.d.ts +26 -0
- package/types/lib/inventory/ciParsers/jenkins.d.ts.map +1 -0
- package/types/lib/inventory/citations.d.ts +90 -0
- package/types/lib/inventory/citations.d.ts.map +1 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts +14 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -0
- package/types/lib/inventory/containerRisk.d.ts +20 -0
- package/types/lib/inventory/containerRisk.d.ts.map +1 -0
- package/types/lib/inventory/cryptoAlgorithmFamily.d.ts +37 -0
- package/types/lib/inventory/cryptoAlgorithmFamily.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +140 -0
- package/types/lib/inventory/deps.d.ts.map +1 -0
- package/types/lib/inventory/depsUtils.d.ts +74 -0
- package/types/lib/inventory/depsUtils.d.ts.map +1 -0
- package/types/lib/inventory/display.d.ts +227 -0
- package/types/lib/inventory/display.d.ts.map +1 -0
- package/types/lib/inventory/dosai.d.ts +130 -0
- package/types/lib/inventory/dosai.d.ts.map +1 -0
- package/types/lib/inventory/dosaiParsers.d.ts +59 -0
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -0
- package/types/lib/inventory/dynamic.d.ts +25 -0
- package/types/lib/inventory/dynamic.d.ts.map +1 -0
- package/types/lib/inventory/envcontext.d.ts +377 -0
- package/types/lib/inventory/envcontext.d.ts.map +1 -0
- package/types/lib/inventory/evidenceUtils.d.ts +74 -0
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -0
- package/types/lib/inventory/fetchBatch.d.ts +127 -0
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -0
- package/types/lib/inventory/fetchRate.d.ts +118 -0
- package/types/lib/inventory/fetchRate.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts +31 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -0
- package/types/lib/inventory/formulationParsers.d.ts +50 -0
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -0
- package/types/lib/inventory/gtfobins.d.ts +27 -0
- package/types/lib/inventory/gtfobins.d.ts.map +1 -0
- package/types/lib/inventory/hbom.d.ts +58 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -0
- package/types/lib/inventory/hbomAnalysis.d.ts +56 -0
- package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/inventory/hbomLoader.d.ts +7 -0
- package/types/lib/inventory/hbomLoader.d.ts.map +1 -0
- package/types/lib/inventory/hostTopology.d.ts +47 -0
- package/types/lib/inventory/hostTopology.d.ts.map +1 -0
- package/types/lib/inventory/inventoryStats.d.ts +42 -0
- package/types/lib/inventory/inventoryStats.d.ts.map +1 -0
- package/types/lib/inventory/jsonLike.d.ts +23 -0
- package/types/lib/inventory/jsonLike.d.ts.map +1 -0
- package/types/lib/inventory/licenseEnhancer.d.ts +70 -0
- package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -0
- package/types/lib/inventory/lolbas.d.ts +16 -0
- package/types/lib/inventory/lolbas.d.ts.map +1 -0
- package/types/lib/inventory/mcp.d.ts +29 -0
- package/types/lib/inventory/mcp.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts +20 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -0
- package/types/lib/inventory/mcpDiscovery.d.ts +33 -0
- package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -0
- package/types/lib/inventory/mcpPinning.d.ts +11 -0
- package/types/lib/inventory/mcpPinning.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +49 -0
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -0
- package/types/lib/inventory/osinfo.d.ts +201 -0
- package/types/lib/inventory/osinfo.d.ts.map +1 -0
- package/types/lib/inventory/osqueryTransform.d.ts +84 -0
- package/types/lib/inventory/osqueryTransform.d.ts.map +1 -0
- package/types/lib/inventory/plugins.d.ts +58 -0
- package/types/lib/inventory/plugins.d.ts.map +1 -0
- package/types/lib/inventory/protobom.d.ts +71 -0
- package/types/lib/inventory/protobom.d.ts.map +1 -0
- package/types/lib/inventory/protobomLoader.d.ts +17 -0
- package/types/lib/inventory/protobomLoader.d.ts.map +1 -0
- package/types/lib/inventory/provenanceUtils.d.ts +98 -0
- package/types/lib/inventory/provenanceUtils.d.ts.map +1 -0
- package/types/lib/inventory/purl.d.ts +313 -0
- package/types/lib/inventory/purl.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts +17 -0
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -0
- package/types/lib/inventory/sbomDocument.d.ts +59 -0
- package/types/lib/inventory/sbomDocument.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +163 -0
- package/types/lib/inventory/source.d.ts.map +1 -0
- package/types/lib/inventory/spdx.d.ts +66 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -0
- package/types/lib/inventory/spdxExpression.d.ts +58 -0
- package/types/lib/inventory/spdxExpression.d.ts.map +1 -0
- package/types/lib/inventory/spdxUtils.d.ts +12 -0
- package/types/lib/inventory/spdxUtils.d.ts.map +1 -0
- package/types/lib/inventory/table.d.ts +22 -0
- package/types/lib/inventory/table.d.ts.map +1 -0
- package/types/lib/inventory/traceRunner.d.ts +80 -0
- package/types/lib/inventory/traceRunner.d.ts.map +1 -0
- package/types/lib/inventory/unicodeScan.d.ts +46 -0
- package/types/lib/inventory/unicodeScan.d.ts.map +1 -0
- package/types/lib/managers/binary.d.ts +147 -0
- package/types/lib/managers/binary.d.ts.map +1 -0
- package/types/lib/managers/containerutils.d.ts +30 -0
- package/types/lib/managers/containerutils.d.ts.map +1 -0
- package/types/lib/managers/docker.d.ts +157 -0
- package/types/lib/managers/docker.d.ts.map +1 -0
- package/types/lib/managers/dockerConnection.d.ts +42 -0
- package/types/lib/managers/dockerConnection.d.ts.map +1 -0
- package/types/lib/managers/oci.d.ts +21 -0
- package/types/lib/managers/oci.d.ts.map +1 -0
- package/types/lib/managers/piptree.d.ts +13 -0
- package/types/lib/managers/piptree.d.ts.map +1 -0
- package/types/lib/parsers/cmakeCache.d.ts +70 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -0
- package/types/lib/parsers/gguf.d.ts +39 -0
- package/types/lib/parsers/gguf.d.ts.map +1 -0
- package/types/lib/parsers/gitAiNotes.d.ts +15 -0
- package/types/lib/parsers/gitAiNotes.d.ts.map +1 -0
- package/types/lib/parsers/gitmodules.d.ts +88 -0
- package/types/lib/parsers/gitmodules.d.ts.map +1 -0
- package/types/lib/parsers/htmlExtract.d.ts +34 -0
- package/types/lib/parsers/htmlExtract.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceManifest.d.ts +153 -0
- package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts +155 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -0
- package/types/lib/parsers/iri.d.ts +68 -0
- package/types/lib/parsers/iri.d.ts.map +1 -0
- package/types/lib/parsers/npmrc.d.ts +33 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -0
- package/types/lib/parsers/ollama.d.ts +22 -0
- package/types/lib/parsers/ollama.d.ts.map +1 -0
- package/types/lib/parsers/xml.d.ts +47 -0
- package/types/lib/parsers/xml.d.ts.map +1 -0
- package/types/lib/server/server.d.ts +51 -0
- package/types/lib/server/server.d.ts.map +1 -0
- package/types/lib/stages/postgen/annotator.d.ts +36 -0
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -0
- package/types/lib/stages/postgen/auditBom.d.ts +92 -0
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/postgen.d.ts +59 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
- package/types/lib/stages/postgen/sortBom.d.ts +34 -0
- package/types/lib/stages/postgen/sortBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts +11 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts.map +1 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts +71 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -0
- package/types/lib/stages/pregen/envAudit.d.ts +14 -0
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
- package/types/lib/stages/pregen/pregen.d.ts +59 -0
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts +47 -0
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts +4 -0
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts +4 -0
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/bin-links.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/bin-links.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts +9 -0
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/debug.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/debug.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/dep-valid.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/dep-valid.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/edge.d.ts +46 -0
- package/types/lib/third-party/arborist/lib/edge.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/from-path.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/from-path.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/index.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/index.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/inventory.d.ts +14 -0
- package/types/lib/third-party/arborist/lib/inventory.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/link.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/link.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/node.d.ts +112 -0
- package/types/lib/third-party/arborist/lib/node.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/npm-extension.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/npm-extension.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/override-resolves.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/override-resolves.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/override-set.d.ts +27 -0
- package/types/lib/third-party/arborist/lib/override-set.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/package-extensions.d.ts +36 -0
- package/types/lib/third-party/arborist/lib/package-extensions.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/printable.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/printable.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/proc-log.d.ts +20 -0
- package/types/lib/third-party/arborist/lib/proc-log.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/realpath.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/realpath.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/relpath.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/relpath.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts +54 -0
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/tree-check.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/tree-check.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts +13 -0
- package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts +6 -0
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts +35 -0
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts.map +1 -0
- package/types/lib/validator/bomValidator.d.ts +40 -0
- package/types/lib/validator/bomValidator.d.ts.map +1 -0
- package/types/lib/validator/complianceEngine.d.ts +72 -0
- package/types/lib/validator/complianceEngine.d.ts.map +1 -0
- package/types/lib/validator/complianceRules.d.ts +61 -0
- package/types/lib/validator/complianceRules.d.ts.map +1 -0
- package/types/lib/validator/index.d.ts +101 -0
- package/types/lib/validator/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/annotations.d.ts +37 -0
- package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
- package/types/lib/validator/reporters/console.d.ts +34 -0
- package/types/lib/validator/reporters/console.d.ts.map +1 -0
- package/types/lib/validator/reporters/index.d.ts +30 -0
- package/types/lib/validator/reporters/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/json.d.ts +11 -0
- package/types/lib/validator/reporters/json.d.ts.map +1 -0
- package/types/lib/validator/reporters/sarif.d.ts +22 -0
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
- package/mod.d.ts +0 -7
- package/mod.js +0 -22
|
@@ -0,0 +1,1087 @@
|
|
|
1
|
+
import path, { basename, extname, relative, resolve } from "node:path";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
|
|
4
|
+
import { createHttpClient, getDefaultHttpTimeoutMs } from "./httpClient.js";
|
|
5
|
+
import { traceLog } from "./logger.js";
|
|
6
|
+
import { CDXGEN_VERSION } from "./state.js";
|
|
7
|
+
|
|
8
|
+
/** True when CDXGEN_DEBUG_MODE or SCAN_DEBUG_MODE requests debug/verbose output. */
|
|
9
|
+
export const DEBUG_MODE =
|
|
10
|
+
["debug", "verbose"].includes(process.env.CDXGEN_DEBUG_MODE) ||
|
|
11
|
+
process.env.SCAN_DEBUG_MODE === "debug";
|
|
12
|
+
|
|
13
|
+
/** True when cdxgen runs in secure/permission-restricted mode (CDXGEN_SECURE_MODE or Node.js --permission). */
|
|
14
|
+
export const isSecureMode =
|
|
15
|
+
["true", "1"].includes(process.env?.CDXGEN_SECURE_MODE) ||
|
|
16
|
+
process.env?.NODE_OPTIONS?.includes("--permission");
|
|
17
|
+
|
|
18
|
+
// CLI dry-run must be detected during module initialization because some probes
|
|
19
|
+
// execute while modules are imported, before bin/cdxgen.js can thread options.
|
|
20
|
+
const hasDryRunArg = process.argv?.some(
|
|
21
|
+
(arg) =>
|
|
22
|
+
arg === "--dry-run" || arg === "--dry-run=true" || arg === "--dry-run=1",
|
|
23
|
+
);
|
|
24
|
+
/** Mutable flag indicating dry-run mode; when true, filesystem, network, and process activity is blocked and recorded instead of executed. */
|
|
25
|
+
export let isDryRun =
|
|
26
|
+
["true", "1"].includes(process.env?.CDXGEN_DRY_RUN) || hasDryRunArg;
|
|
27
|
+
|
|
28
|
+
/** Error code string attached to errors raised when an operation is blocked by dry-run mode. */
|
|
29
|
+
export const DRY_RUN_ERROR_CODE = "CDXGEN_DRY_RUN";
|
|
30
|
+
const activityLedger = [];
|
|
31
|
+
let activityCounter = 0;
|
|
32
|
+
let currentActivityContext = {};
|
|
33
|
+
const dryRunReadTraceState =
|
|
34
|
+
globalThis.__cdxgenDryRunReadTraceState ||
|
|
35
|
+
(globalThis.__cdxgenDryRunReadTraceState = {
|
|
36
|
+
environmentReads: new Map(),
|
|
37
|
+
observations: new Map(),
|
|
38
|
+
recordActivity: undefined,
|
|
39
|
+
sensitiveFileReads: new Map(),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const SENSITIVE_ENV_VAR_PATTERN =
|
|
43
|
+
/(^|_)(?:token|key|secret|pass(?:word)?|credential(?:s)?|cred|auth|session|cookie|email|user)$/i;
|
|
44
|
+
const DIRECTORY_DISCOVERY_NAMES = new Set([
|
|
45
|
+
".cargo",
|
|
46
|
+
".docker",
|
|
47
|
+
".gem",
|
|
48
|
+
".github",
|
|
49
|
+
".m2",
|
|
50
|
+
".nuget",
|
|
51
|
+
".venv",
|
|
52
|
+
".yarn",
|
|
53
|
+
"blobs",
|
|
54
|
+
"extensions",
|
|
55
|
+
"node_modules",
|
|
56
|
+
"target",
|
|
57
|
+
"vendor",
|
|
58
|
+
]);
|
|
59
|
+
const LOCKFILE_ACTIVITY_HINTS = new Map([
|
|
60
|
+
[
|
|
61
|
+
"bun.lock",
|
|
62
|
+
{ classification: "lockfile", ecosystem: "bun", label: "Bun lockfile" },
|
|
63
|
+
],
|
|
64
|
+
[
|
|
65
|
+
"cargo.lock",
|
|
66
|
+
{ classification: "lockfile", ecosystem: "cargo", label: "Cargo lockfile" },
|
|
67
|
+
],
|
|
68
|
+
[
|
|
69
|
+
"composer.lock",
|
|
70
|
+
{
|
|
71
|
+
classification: "lockfile",
|
|
72
|
+
ecosystem: "composer",
|
|
73
|
+
label: "Composer lockfile",
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
[
|
|
77
|
+
"deno.lock",
|
|
78
|
+
{ classification: "lockfile", ecosystem: "deno", label: "Deno lockfile" },
|
|
79
|
+
],
|
|
80
|
+
[
|
|
81
|
+
"gemfile.lock",
|
|
82
|
+
{
|
|
83
|
+
classification: "lockfile",
|
|
84
|
+
ecosystem: "rubygems",
|
|
85
|
+
label: "Bundler lockfile",
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
[
|
|
89
|
+
"package-lock.json",
|
|
90
|
+
{ classification: "lockfile", ecosystem: "npm", label: "npm lockfile" },
|
|
91
|
+
],
|
|
92
|
+
[
|
|
93
|
+
"packages.lock.json",
|
|
94
|
+
{ classification: "lockfile", ecosystem: "nuget", label: "NuGet lockfile" },
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
"pdm.lock",
|
|
98
|
+
{ classification: "lockfile", ecosystem: "python", label: "PDM lockfile" },
|
|
99
|
+
],
|
|
100
|
+
[
|
|
101
|
+
"pnpm-lock.yaml",
|
|
102
|
+
{ classification: "lockfile", ecosystem: "pnpm", label: "pnpm lockfile" },
|
|
103
|
+
],
|
|
104
|
+
[
|
|
105
|
+
"poetry.lock",
|
|
106
|
+
{
|
|
107
|
+
classification: "lockfile",
|
|
108
|
+
ecosystem: "python",
|
|
109
|
+
label: "Poetry lockfile",
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
[
|
|
113
|
+
"podfile.lock",
|
|
114
|
+
{
|
|
115
|
+
classification: "lockfile",
|
|
116
|
+
ecosystem: "cocoapods",
|
|
117
|
+
label: "CocoaPods lockfile",
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
[
|
|
121
|
+
"pylock.toml",
|
|
122
|
+
{
|
|
123
|
+
classification: "lockfile",
|
|
124
|
+
ecosystem: "python",
|
|
125
|
+
label: "PEP 751 lockfile",
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
[
|
|
129
|
+
"uv.lock",
|
|
130
|
+
{ classification: "lockfile", ecosystem: "python", label: "uv lockfile" },
|
|
131
|
+
],
|
|
132
|
+
[
|
|
133
|
+
"yarn.lock",
|
|
134
|
+
{ classification: "lockfile", ecosystem: "yarn", label: "Yarn lockfile" },
|
|
135
|
+
],
|
|
136
|
+
]);
|
|
137
|
+
const MANIFEST_ACTIVITY_HINTS = new Map([
|
|
138
|
+
[
|
|
139
|
+
"cargo.toml",
|
|
140
|
+
{ classification: "manifest", ecosystem: "cargo", label: "Cargo manifest" },
|
|
141
|
+
],
|
|
142
|
+
[
|
|
143
|
+
"composer.json",
|
|
144
|
+
{
|
|
145
|
+
classification: "manifest",
|
|
146
|
+
ecosystem: "composer",
|
|
147
|
+
label: "Composer manifest",
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
[
|
|
151
|
+
"deno.json",
|
|
152
|
+
{ classification: "manifest", ecosystem: "deno", label: "Deno manifest" },
|
|
153
|
+
],
|
|
154
|
+
[
|
|
155
|
+
"gemfile",
|
|
156
|
+
{
|
|
157
|
+
classification: "manifest",
|
|
158
|
+
ecosystem: "rubygems",
|
|
159
|
+
label: "Gem manifest",
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
[
|
|
163
|
+
"package.json",
|
|
164
|
+
{ classification: "manifest", ecosystem: "npm", label: "package manifest" },
|
|
165
|
+
],
|
|
166
|
+
[
|
|
167
|
+
"pom.xml",
|
|
168
|
+
{ classification: "manifest", ecosystem: "maven", label: "Maven manifest" },
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
"pyproject.toml",
|
|
172
|
+
{
|
|
173
|
+
classification: "manifest",
|
|
174
|
+
ecosystem: "python",
|
|
175
|
+
label: "Python project manifest",
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
[
|
|
179
|
+
"requirements.txt",
|
|
180
|
+
{
|
|
181
|
+
classification: "manifest",
|
|
182
|
+
ecosystem: "python",
|
|
183
|
+
label: "Python requirements manifest",
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
[
|
|
187
|
+
"setup.py",
|
|
188
|
+
{
|
|
189
|
+
classification: "manifest",
|
|
190
|
+
ecosystem: "python",
|
|
191
|
+
label: "Python setup manifest",
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
]);
|
|
195
|
+
const SENSITIVE_CONFIG_ACTIVITY_HINTS = [
|
|
196
|
+
{
|
|
197
|
+
matcher: (lowerPath, _baseName) =>
|
|
198
|
+
lowerPath.includes("/.cargo/config.toml") ||
|
|
199
|
+
lowerPath.endsWith("/.cargo/credentials") ||
|
|
200
|
+
lowerPath.endsWith("/.cargo/credentials.toml"),
|
|
201
|
+
metadata: {
|
|
202
|
+
classification: "config",
|
|
203
|
+
ecosystem: "cargo",
|
|
204
|
+
label: "Cargo registry configuration",
|
|
205
|
+
sensitive: true,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
matcher: (lowerPath, baseName) =>
|
|
210
|
+
lowerPath.includes("/.docker/config.json") ||
|
|
211
|
+
(baseName === "config.json" && lowerPath.includes("/docker")),
|
|
212
|
+
metadata: {
|
|
213
|
+
classification: "credential",
|
|
214
|
+
ecosystem: "oci",
|
|
215
|
+
label: "Docker credential file",
|
|
216
|
+
sensitive: true,
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
matcher: (lowerPath) => lowerPath.endsWith("/.gem/credentials"),
|
|
221
|
+
metadata: {
|
|
222
|
+
classification: "credential",
|
|
223
|
+
ecosystem: "rubygems",
|
|
224
|
+
label: "RubyGems credentials file",
|
|
225
|
+
sensitive: true,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
matcher: (_lowerPath, baseName) =>
|
|
230
|
+
baseName === ".npmrc" || baseName === ".pnpmrc" || baseName === ".yarnrc",
|
|
231
|
+
metadata: {
|
|
232
|
+
classification: "config",
|
|
233
|
+
ecosystem: "npm",
|
|
234
|
+
label: "JavaScript package manager configuration",
|
|
235
|
+
sensitive: true,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
matcher: (_lowerPath, baseName) => baseName === ".yarnrc.yml",
|
|
240
|
+
metadata: {
|
|
241
|
+
classification: "config",
|
|
242
|
+
ecosystem: "yarn",
|
|
243
|
+
label: "Yarn configuration",
|
|
244
|
+
sensitive: true,
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
matcher: (_lowerPath, baseName) =>
|
|
249
|
+
baseName === ".pypirc" || baseName === "pip.conf",
|
|
250
|
+
metadata: {
|
|
251
|
+
classification: "config",
|
|
252
|
+
ecosystem: "python",
|
|
253
|
+
label: "Python package publishing configuration",
|
|
254
|
+
sensitive: true,
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
matcher: (_lowerPath, baseName) =>
|
|
259
|
+
baseName === "uv.toml" || baseName === "poetry.toml",
|
|
260
|
+
metadata: {
|
|
261
|
+
classification: "config",
|
|
262
|
+
ecosystem: "python",
|
|
263
|
+
label: "Python package manager configuration",
|
|
264
|
+
sensitive: true,
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
matcher: (_lowerPath, baseName) => baseName === "nuget.config",
|
|
269
|
+
metadata: {
|
|
270
|
+
classification: "config",
|
|
271
|
+
ecosystem: "nuget",
|
|
272
|
+
label: "NuGet configuration",
|
|
273
|
+
sensitive: true,
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
matcher: (_lowerPath, baseName) => baseName === "settings.xml",
|
|
278
|
+
metadata: {
|
|
279
|
+
classification: "config",
|
|
280
|
+
ecosystem: "maven",
|
|
281
|
+
label: "Maven settings.xml",
|
|
282
|
+
sensitive: true,
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
];
|
|
286
|
+
const CERTIFICATE_FILE_EXTENSIONS = new Set([".crt", ".cer", ".pem"]);
|
|
287
|
+
const KEY_FILE_EXTENSIONS = new Set([
|
|
288
|
+
".key",
|
|
289
|
+
".jks",
|
|
290
|
+
".keystore",
|
|
291
|
+
".p12",
|
|
292
|
+
".pfx",
|
|
293
|
+
]);
|
|
294
|
+
|
|
295
|
+
/** @param {number} count Number of times an activity was observed. @returns {string} Suffix string indicating repeat count, or empty string. */
|
|
296
|
+
const buildReadCountSuffix = (count) => (count > 1 ? ` (${count} times)` : "");
|
|
297
|
+
|
|
298
|
+
const buildEnvironmentReadReason = (varName, count, sensitive) =>
|
|
299
|
+
`Read ${sensitive ? "sensitive " : ""}environment variable ${varName}${buildReadCountSuffix(count)}.`;
|
|
300
|
+
|
|
301
|
+
const buildSensitiveFileReadReason = (filePath, count, label) =>
|
|
302
|
+
`Read ${label} ${filePath}${buildReadCountSuffix(count)}.`;
|
|
303
|
+
|
|
304
|
+
function emitActivity(activity) {
|
|
305
|
+
if (typeof dryRunReadTraceState.recordActivity !== "function") {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
return dryRunReadTraceState.recordActivity(activity);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Classify a filesystem path into an activity metadata object describing its
|
|
313
|
+
* classification (lockfile, manifest, certificate, key, cache, etc.), ecosystem,
|
|
314
|
+
* label, and whether it is sensitive.
|
|
315
|
+
*
|
|
316
|
+
* @param {string} filePath File path to classify.
|
|
317
|
+
* @returns {Object|undefined} Metadata object, or undefined when the path does not match a known pattern.
|
|
318
|
+
*/
|
|
319
|
+
function classifyActivityPath(filePath) {
|
|
320
|
+
if (typeof filePath !== "string" || !filePath.length) {
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
323
|
+
const normalizedPath = filePath.replaceAll("\\", "/");
|
|
324
|
+
const lowerPath = normalizedPath.toLowerCase();
|
|
325
|
+
const baseName = basename(lowerPath);
|
|
326
|
+
if (LOCKFILE_ACTIVITY_HINTS.has(baseName)) {
|
|
327
|
+
return LOCKFILE_ACTIVITY_HINTS.get(baseName);
|
|
328
|
+
}
|
|
329
|
+
if (MANIFEST_ACTIVITY_HINTS.has(baseName)) {
|
|
330
|
+
return MANIFEST_ACTIVITY_HINTS.get(baseName);
|
|
331
|
+
}
|
|
332
|
+
for (const { matcher, metadata } of SENSITIVE_CONFIG_ACTIVITY_HINTS) {
|
|
333
|
+
if (matcher(lowerPath, baseName)) {
|
|
334
|
+
return metadata;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (
|
|
338
|
+
lowerPath.includes("/cache/") ||
|
|
339
|
+
lowerPath.includes("/.cache/") ||
|
|
340
|
+
lowerPath.includes("/caches/")
|
|
341
|
+
) {
|
|
342
|
+
return {
|
|
343
|
+
classification: "cache",
|
|
344
|
+
label: "cache path",
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (
|
|
348
|
+
CERTIFICATE_FILE_EXTENSIONS.has(extname(baseName)) ||
|
|
349
|
+
baseName === "cert.pem"
|
|
350
|
+
) {
|
|
351
|
+
return {
|
|
352
|
+
classification: "certificate",
|
|
353
|
+
label: "certificate file",
|
|
354
|
+
sensitive: true,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
if (
|
|
358
|
+
KEY_FILE_EXTENSIONS.has(extname(baseName)) ||
|
|
359
|
+
baseName === "key.pem" ||
|
|
360
|
+
baseName.startsWith("id_")
|
|
361
|
+
) {
|
|
362
|
+
return {
|
|
363
|
+
classification: "key",
|
|
364
|
+
label: "private key file",
|
|
365
|
+
sensitive: true,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
const trimmedPath = normalizedPath.endsWith("/")
|
|
369
|
+
? normalizedPath.slice(0, -1)
|
|
370
|
+
: normalizedPath;
|
|
371
|
+
const directoryName = basename(trimmedPath.toLowerCase());
|
|
372
|
+
if (DIRECTORY_DISCOVERY_NAMES.has(directoryName)) {
|
|
373
|
+
return {
|
|
374
|
+
classification: "directory",
|
|
375
|
+
label: "directory discovery path",
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
return undefined;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Classify a discovery glob pattern into a discovery type and human-readable label.
|
|
383
|
+
*
|
|
384
|
+
* @param {string|string[]} pattern Glob pattern (or array of patterns) used for discovery.
|
|
385
|
+
* @returns {{discoveryType: string, label: string}} Discovery metadata with a `discoveryType` and `label`.
|
|
386
|
+
*/
|
|
387
|
+
function classifyDiscoveryPattern(pattern) {
|
|
388
|
+
const patternValue = Array.isArray(pattern)
|
|
389
|
+
? pattern.join(",")
|
|
390
|
+
: String(pattern);
|
|
391
|
+
const lowerPattern = patternValue.toLowerCase();
|
|
392
|
+
if (
|
|
393
|
+
lowerPattern.includes("package-lock.json") ||
|
|
394
|
+
lowerPattern.includes("pnpm-lock.yaml") ||
|
|
395
|
+
lowerPattern.includes("yarn.lock") ||
|
|
396
|
+
lowerPattern.includes("poetry.lock") ||
|
|
397
|
+
lowerPattern.includes("uv.lock") ||
|
|
398
|
+
lowerPattern.includes("cargo.lock") ||
|
|
399
|
+
lowerPattern.includes("gemfile.lock")
|
|
400
|
+
) {
|
|
401
|
+
return {
|
|
402
|
+
discoveryType: "lockfile-discovery",
|
|
403
|
+
label: "lockfile discovery",
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
if (
|
|
407
|
+
lowerPattern.includes("package.json") ||
|
|
408
|
+
lowerPattern.includes("pom.xml") ||
|
|
409
|
+
lowerPattern.includes("pyproject.toml") ||
|
|
410
|
+
lowerPattern.includes("cargo.toml") ||
|
|
411
|
+
lowerPattern.includes("composer.json")
|
|
412
|
+
) {
|
|
413
|
+
return {
|
|
414
|
+
discoveryType: "manifest-discovery",
|
|
415
|
+
label: "manifest discovery",
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
discoveryType: "directory-enumeration",
|
|
420
|
+
label: "directory enumeration",
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function recordDeduplicatedRead(traceMap, traceKey, activity, createReason) {
|
|
425
|
+
const existingTrace = traceMap.get(traceKey);
|
|
426
|
+
if (existingTrace) {
|
|
427
|
+
existingTrace.count += 1;
|
|
428
|
+
if (existingTrace.entry) {
|
|
429
|
+
existingTrace.entry.count = existingTrace.count;
|
|
430
|
+
existingTrace.entry.reason = createReason(existingTrace.count);
|
|
431
|
+
}
|
|
432
|
+
return existingTrace.entry;
|
|
433
|
+
}
|
|
434
|
+
const entry = emitActivity({
|
|
435
|
+
...activity,
|
|
436
|
+
reason: createReason(1),
|
|
437
|
+
});
|
|
438
|
+
if (entry) {
|
|
439
|
+
entry.count = 1;
|
|
440
|
+
}
|
|
441
|
+
traceMap.set(traceKey, {
|
|
442
|
+
count: 1,
|
|
443
|
+
entry,
|
|
444
|
+
});
|
|
445
|
+
return entry;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Tests whether an environment variable name matches sensitive patterns
|
|
450
|
+
* (token, key, secret, password, credential, auth, session, cookie, etc.).
|
|
451
|
+
*
|
|
452
|
+
* @param {string} varName Environment variable name to test.
|
|
453
|
+
* @returns {boolean} True when the name matches a sensitive pattern.
|
|
454
|
+
*/
|
|
455
|
+
export function isSensitiveEnvironmentVariableName(varName) {
|
|
456
|
+
return typeof varName === "string" && SENSITIVE_ENV_VAR_PATTERN.test(varName);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Record a deduplicated observed activity entry (filesystem, environment, or
|
|
461
|
+
* discovery). No-op unless dry-run or debug mode is active.
|
|
462
|
+
*
|
|
463
|
+
* @param {string} kind Activity kind (e.g. "inspect", "discover", "decision").
|
|
464
|
+
* @param {string} target Activity target (path, host, or identifier).
|
|
465
|
+
* @param {Object} [options] Optional metadata including `status`, `reason`, `reasonBuilder`, `metadata`, `traceKey`, and `traceDetail`.
|
|
466
|
+
* @returns {Object|undefined} The recorded activity entry, or undefined.
|
|
467
|
+
*/
|
|
468
|
+
export function recordObservedActivity(kind, target, options = {}) {
|
|
469
|
+
if (!(isDryRun || DEBUG_MODE) || !kind || !target) {
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
const status = options.status || "completed";
|
|
473
|
+
const traceKey =
|
|
474
|
+
options.traceKey ||
|
|
475
|
+
`${kind}:${status}:${target}:${options.traceDetail || ""}`;
|
|
476
|
+
const metadata = options.metadata || {};
|
|
477
|
+
const reasonBuilder =
|
|
478
|
+
options.reasonBuilder ||
|
|
479
|
+
((count) =>
|
|
480
|
+
options.reason
|
|
481
|
+
? `${options.reason}${buildReadCountSuffix(count)}`
|
|
482
|
+
: `Recorded ${kind} activity for ${target}${buildReadCountSuffix(count)}.`);
|
|
483
|
+
return recordDeduplicatedRead(
|
|
484
|
+
dryRunReadTraceState.observations,
|
|
485
|
+
traceKey,
|
|
486
|
+
{
|
|
487
|
+
kind,
|
|
488
|
+
status,
|
|
489
|
+
target,
|
|
490
|
+
...metadata,
|
|
491
|
+
},
|
|
492
|
+
reasonBuilder,
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/** @param {string} target Activity target. @param {Object} [options] Options forwarded to recordObservedActivity. @returns {Object|undefined} Recorded activity entry. */
|
|
497
|
+
export function recordDecisionActivity(target, options = {}) {
|
|
498
|
+
return recordObservedActivity(options.kind || "decision", target, options);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/** @param {string} target Activity target. @param {Object} [options] Options forwarded to recordObservedActivity. @returns {Object|undefined} Recorded activity entry. */
|
|
502
|
+
export function recordDiscoveryActivity(target, options = {}) {
|
|
503
|
+
return recordObservedActivity(options.kind || "discover", target, options);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** @param {string} target Activity target. @param {Object} [options] Options forwarded to recordObservedActivity. @returns {Object|undefined} Recorded activity entry. */
|
|
507
|
+
export function recordPolicyActivity(target, options = {}) {
|
|
508
|
+
return recordObservedActivity(options.kind || "policy", target, options);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function normalizeRecordedPathForComparison(
|
|
512
|
+
candidatePath,
|
|
513
|
+
basePath = undefined,
|
|
514
|
+
) {
|
|
515
|
+
if (typeof candidatePath !== "string" || !candidatePath.length) {
|
|
516
|
+
return undefined;
|
|
517
|
+
}
|
|
518
|
+
let normalizedPath = candidatePath.replaceAll("\\", "/");
|
|
519
|
+
if (basePath && path.isAbsolute(candidatePath)) {
|
|
520
|
+
const resolvedBasePath = resolve(basePath);
|
|
521
|
+
const normalizedBasePath = resolvedBasePath.replaceAll("\\", "/");
|
|
522
|
+
const isWithinBasePath = (candidate) => {
|
|
523
|
+
const normalizedCandidate = candidate.replaceAll("\\", "/");
|
|
524
|
+
return (
|
|
525
|
+
normalizedCandidate === normalizedBasePath ||
|
|
526
|
+
normalizedCandidate.startsWith(`${normalizedBasePath}/`)
|
|
527
|
+
);
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
const resolvedCandidatePath = resolve(candidatePath);
|
|
531
|
+
if (isWithinBasePath(resolvedCandidatePath)) {
|
|
532
|
+
normalizedPath = relative(
|
|
533
|
+
resolvedBasePath,
|
|
534
|
+
resolvedCandidatePath,
|
|
535
|
+
).replaceAll("\\", "/");
|
|
536
|
+
} else {
|
|
537
|
+
const rebasedCandidatePath = resolve(
|
|
538
|
+
resolvedBasePath,
|
|
539
|
+
candidatePath.replace(/^([A-Za-z]:)?[\\/]+/, ""),
|
|
540
|
+
);
|
|
541
|
+
if (isWithinBasePath(rebasedCandidatePath)) {
|
|
542
|
+
normalizedPath = relative(
|
|
543
|
+
resolvedBasePath,
|
|
544
|
+
rebasedCandidatePath,
|
|
545
|
+
).replaceAll("\\", "/");
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return normalizedPath;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Record a symlink resolution outcome, normalizing both paths relative to an
|
|
554
|
+
* optional base path.
|
|
555
|
+
*
|
|
556
|
+
* @param {string} sourcePath The symlink source path.
|
|
557
|
+
* @param {string} resolvedPath The resolved target path.
|
|
558
|
+
* @param {Object} [options] Options including `basePath`, `status`, `reason`, `errorCode`, and `metadata`.
|
|
559
|
+
* @returns {Object|undefined} Recorded activity entry, or undefined.
|
|
560
|
+
*/
|
|
561
|
+
export function recordSymlinkResolution(
|
|
562
|
+
sourcePath,
|
|
563
|
+
resolvedPath,
|
|
564
|
+
options = {},
|
|
565
|
+
) {
|
|
566
|
+
const normalizedSourcePath = normalizeRecordedPathForComparison(
|
|
567
|
+
sourcePath,
|
|
568
|
+
options.basePath,
|
|
569
|
+
);
|
|
570
|
+
const normalizedResolvedPath = normalizeRecordedPathForComparison(
|
|
571
|
+
resolvedPath,
|
|
572
|
+
options.basePath,
|
|
573
|
+
);
|
|
574
|
+
const status = options.status || "completed";
|
|
575
|
+
if (
|
|
576
|
+
!normalizedSourcePath ||
|
|
577
|
+
(status === "completed" &&
|
|
578
|
+
(!normalizedResolvedPath ||
|
|
579
|
+
normalizedSourcePath === normalizedResolvedPath))
|
|
580
|
+
) {
|
|
581
|
+
return undefined;
|
|
582
|
+
}
|
|
583
|
+
const metadata = {
|
|
584
|
+
capability: "symlink-resolution",
|
|
585
|
+
...(normalizedResolvedPath ? { resolvedPath: normalizedResolvedPath } : {}),
|
|
586
|
+
...(options.errorCode ? { errorCode: options.errorCode } : {}),
|
|
587
|
+
...(options.metadata || {}),
|
|
588
|
+
};
|
|
589
|
+
return recordObservedActivity("symlink-resolution", normalizedSourcePath, {
|
|
590
|
+
metadata,
|
|
591
|
+
reason:
|
|
592
|
+
options.reason ||
|
|
593
|
+
(status === "failed"
|
|
594
|
+
? `Failed to resolve symlink ${normalizedSourcePath}.`
|
|
595
|
+
: `Resolved symlink ${normalizedSourcePath} to ${normalizedResolvedPath}.`),
|
|
596
|
+
status,
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Record a deduplicated environment-variable read, flagging names that match
|
|
602
|
+
* sensitive patterns.
|
|
603
|
+
*
|
|
604
|
+
* @param {string} varName Environment variable name that was read.
|
|
605
|
+
* @param {Object} [options] Options including `source`, `sensitive`, `status`, and `reason`.
|
|
606
|
+
* @returns {Object|undefined} Recorded activity entry, or undefined.
|
|
607
|
+
*/
|
|
608
|
+
export function recordEnvironmentRead(varName, options = {}) {
|
|
609
|
+
// Read tracing intentionally mirrors the activity ledger's dry-run/debug behavior.
|
|
610
|
+
if (!(isDryRun || DEBUG_MODE) || !varName) {
|
|
611
|
+
return undefined;
|
|
612
|
+
}
|
|
613
|
+
const source = options.source || "process.env";
|
|
614
|
+
const sensitive =
|
|
615
|
+
options.sensitive ?? isSensitiveEnvironmentVariableName(varName);
|
|
616
|
+
const status = options.status || "completed";
|
|
617
|
+
const traceKey = `${source}:${varName}:${status}`;
|
|
618
|
+
const target = `${source}:${varName}`;
|
|
619
|
+
return recordDeduplicatedRead(
|
|
620
|
+
dryRunReadTraceState.environmentReads,
|
|
621
|
+
traceKey,
|
|
622
|
+
{
|
|
623
|
+
kind: "env",
|
|
624
|
+
redacted: sensitive,
|
|
625
|
+
secretCategory: sensitive ? "environment-variable" : undefined,
|
|
626
|
+
sensitive,
|
|
627
|
+
status,
|
|
628
|
+
target,
|
|
629
|
+
},
|
|
630
|
+
(count) =>
|
|
631
|
+
options.reason || buildEnvironmentReadReason(varName, count, sensitive),
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Record a sensitive-file read, deriving classification metadata from the path.
|
|
637
|
+
*
|
|
638
|
+
* @param {string} filePath Path of the sensitive file that was read.
|
|
639
|
+
* @param {Object} [options] Options including `kind`, `label`, `status`, and `reason`.
|
|
640
|
+
* @returns {Object|undefined} Recorded activity entry, or undefined.
|
|
641
|
+
*/
|
|
642
|
+
export function recordSensitiveFileRead(filePath, options = {}) {
|
|
643
|
+
// Read tracing intentionally mirrors the activity ledger's dry-run/debug behavior.
|
|
644
|
+
if (!(isDryRun || DEBUG_MODE) || !filePath) {
|
|
645
|
+
return undefined;
|
|
646
|
+
}
|
|
647
|
+
const kind = options.kind || "read";
|
|
648
|
+
const pathMetadata = classifyActivityPath(filePath) || {};
|
|
649
|
+
const label = options.label || pathMetadata.label || "sensitive file";
|
|
650
|
+
const status = options.status || "completed";
|
|
651
|
+
const traceKey = `${kind}:${status}:${filePath}`;
|
|
652
|
+
return recordDeduplicatedRead(
|
|
653
|
+
dryRunReadTraceState.sensitiveFileReads,
|
|
654
|
+
traceKey,
|
|
655
|
+
{
|
|
656
|
+
classification: pathMetadata.classification,
|
|
657
|
+
ecosystem: pathMetadata.ecosystem,
|
|
658
|
+
kind,
|
|
659
|
+
redacted: pathMetadata.sensitive ?? true,
|
|
660
|
+
secretCategory:
|
|
661
|
+
pathMetadata.classification === "key"
|
|
662
|
+
? "private-key"
|
|
663
|
+
: pathMetadata.classification === "certificate"
|
|
664
|
+
? "certificate"
|
|
665
|
+
: "credential-file",
|
|
666
|
+
status,
|
|
667
|
+
target: filePath,
|
|
668
|
+
},
|
|
669
|
+
(count) =>
|
|
670
|
+
options.reason || buildSensitiveFileReadReason(filePath, count, label),
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Read an environment variable while recording the read for activity tracing.
|
|
676
|
+
*
|
|
677
|
+
* @param {string} varName Environment variable name to read.
|
|
678
|
+
* @param {Object} [options] Options forwarded to recordEnvironmentRead.
|
|
679
|
+
* @returns {string|undefined} The variable value, or undefined when unset.
|
|
680
|
+
*/
|
|
681
|
+
export function readEnvironmentVariable(varName, options = {}) {
|
|
682
|
+
recordEnvironmentRead(varName, options);
|
|
683
|
+
return process.env[varName];
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Toggle dry-run mode on or off and keep the CDXGEN_DRY_RUN environment variable in sync.
|
|
688
|
+
*
|
|
689
|
+
* @param {boolean} enabled True to enable dry-run mode, false to disable.
|
|
690
|
+
* @returns {void}
|
|
691
|
+
*/
|
|
692
|
+
export function setDryRunMode(enabled) {
|
|
693
|
+
isDryRun = !!enabled;
|
|
694
|
+
if (enabled) {
|
|
695
|
+
process.env.CDXGEN_DRY_RUN = "true";
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
delete process.env.CDXGEN_DRY_RUN;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Construct an Error tagged as a dry-run-blocked operation.
|
|
703
|
+
*
|
|
704
|
+
* @param {string} action Action that was blocked (e.g. "network", "execute").
|
|
705
|
+
* @param {string} target Target of the blocked action.
|
|
706
|
+
* @param {string} [reason] Optional human-readable reason; defaults to a generic message.
|
|
707
|
+
* @returns {Error} Error with `code`, `action`, `target`, and `dryRun` properties set.
|
|
708
|
+
*/
|
|
709
|
+
export function createDryRunError(action, target, reason) {
|
|
710
|
+
const message =
|
|
711
|
+
reason || `Dry run mode blocked the attempted ${action} operation.`;
|
|
712
|
+
const error = new Error(message);
|
|
713
|
+
error.code = DRY_RUN_ERROR_CODE;
|
|
714
|
+
error.name = "DryRunError";
|
|
715
|
+
error.action = action;
|
|
716
|
+
error.target = target;
|
|
717
|
+
error.dryRun = true;
|
|
718
|
+
return error;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Returns true when the given error was produced by dry-run blocking.
|
|
723
|
+
*
|
|
724
|
+
* @param {Error} error Error to inspect.
|
|
725
|
+
* @returns {boolean} True when the error carries the dry-run code or flag.
|
|
726
|
+
*/
|
|
727
|
+
export function isDryRunError(error) {
|
|
728
|
+
return !!(error?.dryRun || error?.code === DRY_RUN_ERROR_CODE);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/** Error code string attached to errors raised when a request is blocked by the host allow-list or secure-mode policy. */
|
|
732
|
+
export const BLOCKED_HOST_ERROR_CODE = "CDXGEN_HOST_BLOCKED";
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Create an error used to abort a request to a host that policy disallows
|
|
736
|
+
* (CDXGEN_ALLOWED_HOSTS or the secure-mode https-only restriction). The
|
|
737
|
+
* beforeRequest hook must throw this so the request is actually aborted;
|
|
738
|
+
* returning does not stop the request.
|
|
739
|
+
*
|
|
740
|
+
* @param {string} target The blocked request URL.
|
|
741
|
+
* @param {string} reason Human readable reason for the block.
|
|
742
|
+
* @returns {Error} Error carrying the blocked-host code.
|
|
743
|
+
*/
|
|
744
|
+
export function createBlockedHostError(target, reason) {
|
|
745
|
+
const error = new Error(reason);
|
|
746
|
+
error.code = BLOCKED_HOST_ERROR_CODE;
|
|
747
|
+
error.name = "BlockedHostError";
|
|
748
|
+
error.target = target;
|
|
749
|
+
error.blockedHost = true;
|
|
750
|
+
return error;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Merge context metadata into the current activity context applied to every recorded activity.
|
|
755
|
+
*
|
|
756
|
+
* @param {Object} [context] Context properties to merge.
|
|
757
|
+
* @returns {void}
|
|
758
|
+
*/
|
|
759
|
+
export function setActivityContext(context = {}) {
|
|
760
|
+
currentActivityContext = {
|
|
761
|
+
...currentActivityContext,
|
|
762
|
+
...context,
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/** Clear the current activity context. @returns {void} */
|
|
767
|
+
export function resetActivityContext() {
|
|
768
|
+
currentActivityContext = {};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Append a timestamped activity entry to the ledger and emit a trace log.
|
|
773
|
+
* No-op unless dry-run or debug mode is active.
|
|
774
|
+
*
|
|
775
|
+
* @param {Object} activity Activity properties to record.
|
|
776
|
+
* @returns {Object|undefined} The recorded, identified entry, or undefined when recording is inactive.
|
|
777
|
+
*/
|
|
778
|
+
export function recordActivity(activity) {
|
|
779
|
+
if (!(isDryRun || DEBUG_MODE)) {
|
|
780
|
+
return undefined;
|
|
781
|
+
}
|
|
782
|
+
const identifier = `ACT-${String(++activityCounter).padStart(4, "0")}`;
|
|
783
|
+
const entry = {
|
|
784
|
+
identifier,
|
|
785
|
+
...currentActivityContext,
|
|
786
|
+
timestamp: new Date().toISOString(),
|
|
787
|
+
...activity,
|
|
788
|
+
};
|
|
789
|
+
activityLedger.push(entry);
|
|
790
|
+
traceLog("activity", entry);
|
|
791
|
+
return entry;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
dryRunReadTraceState.recordActivity = recordActivity;
|
|
795
|
+
|
|
796
|
+
/** @returns {Object[]} Shallow copy of the recorded activity ledger. */
|
|
797
|
+
export function getRecordedActivities() {
|
|
798
|
+
return [...activityLedger];
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/** Clear the activity ledger and all dedup maps. @returns {void} */
|
|
802
|
+
export function resetRecordedActivities() {
|
|
803
|
+
activityLedger.length = 0;
|
|
804
|
+
activityCounter = 0;
|
|
805
|
+
dryRunReadTraceState.environmentReads.clear();
|
|
806
|
+
dryRunReadTraceState.observations.clear();
|
|
807
|
+
dryRunReadTraceState.sensitiveFileReads.clear();
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Record a filesystem activity entry with the given kind, target, and status.
|
|
812
|
+
*
|
|
813
|
+
* @param {string} kind Activity kind (e.g. "write", "mkdir", "cleanup").
|
|
814
|
+
* @param {string} target Filesystem target path.
|
|
815
|
+
* @param {string} status Activity status (e.g. "completed", "blocked").
|
|
816
|
+
* @param {string} [reason] Optional human-readable reason.
|
|
817
|
+
* @param {Object} [metadata] Optional additional metadata.
|
|
818
|
+
* @returns {Object|undefined} Recorded activity entry, or undefined.
|
|
819
|
+
*/
|
|
820
|
+
function recordFilesystemActivity(
|
|
821
|
+
kind,
|
|
822
|
+
target,
|
|
823
|
+
status,
|
|
824
|
+
reason = undefined,
|
|
825
|
+
metadata = {},
|
|
826
|
+
) {
|
|
827
|
+
return recordActivity({
|
|
828
|
+
kind,
|
|
829
|
+
...metadata,
|
|
830
|
+
reason,
|
|
831
|
+
status,
|
|
832
|
+
target,
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/** Set accumulating hostnames of remote hosts contacted during a scan. */
|
|
837
|
+
export const remoteHostsAccessed = new Set();
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Test a hostname against the CDXGEN_ALLOWED_HOSTS allow-list, supporting exact
|
|
841
|
+
* matches and `*.suffix` wildcards. When no allow-list is configured, all hosts are allowed.
|
|
842
|
+
*
|
|
843
|
+
* @param {string} hostname Hostname to test.
|
|
844
|
+
* @param {string} [allowedHostsEnv] Comma-separated allow-list string; defaults to the CDXGEN_ALLOWED_HOSTS env var.
|
|
845
|
+
* @returns {boolean} True when the hostname is permitted.
|
|
846
|
+
*/
|
|
847
|
+
export function isAllowedHttpHost(
|
|
848
|
+
hostname,
|
|
849
|
+
allowedHostsEnv = readEnvironmentVariable("CDXGEN_ALLOWED_HOSTS"),
|
|
850
|
+
) {
|
|
851
|
+
if (!allowedHostsEnv) {
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
if (!hostname || hasDangerousUnicode(hostname)) {
|
|
855
|
+
return false;
|
|
856
|
+
}
|
|
857
|
+
const normalizedHostname = hostname.toLowerCase();
|
|
858
|
+
const allow_hosts = allowedHostsEnv
|
|
859
|
+
.split(",")
|
|
860
|
+
.map((host) => host.trim().toLowerCase())
|
|
861
|
+
.filter(Boolean);
|
|
862
|
+
for (const ahost of allow_hosts) {
|
|
863
|
+
if (normalizedHostname === ahost) {
|
|
864
|
+
return true;
|
|
865
|
+
}
|
|
866
|
+
// wildcard support
|
|
867
|
+
if (
|
|
868
|
+
ahost.startsWith("*.") &&
|
|
869
|
+
normalizedHostname.length > ahost.length - 1 &&
|
|
870
|
+
normalizedHostname.endsWith(`.${ahost.slice(2)}`)
|
|
871
|
+
) {
|
|
872
|
+
return true;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return false;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Checks for dangerous Unicode characters that could enable homograph attacks
|
|
880
|
+
*
|
|
881
|
+
* @param {string} str String to check
|
|
882
|
+
* @returns {boolean} true if dangerous Unicode is found
|
|
883
|
+
*/
|
|
884
|
+
// biome-ignore-start lint/suspicious/noControlCharactersInRegex: validation
|
|
885
|
+
export function hasDangerousUnicode(str) {
|
|
886
|
+
// Check for bidirectional control characters
|
|
887
|
+
const bidiChars = /[\u202A-\u202E\u2066-\u2069]/;
|
|
888
|
+
if (bidiChars.test(str)) {
|
|
889
|
+
return true;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// Check for zero-width characters that could be used for obfuscation
|
|
893
|
+
const zeroWidthChars = /[\u200B-\u200D\uFEFF]/;
|
|
894
|
+
if (zeroWidthChars.test(str)) {
|
|
895
|
+
return true;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// Check for control characters (except common ones like \n, \r, \t)
|
|
899
|
+
const controlChars = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/;
|
|
900
|
+
return controlChars.test(str);
|
|
901
|
+
}
|
|
902
|
+
// biome-ignore-end lint/suspicious/noControlCharactersInRegex: validation
|
|
903
|
+
|
|
904
|
+
function hostnameMatches(hostname, candidateHost) {
|
|
905
|
+
return hostname === candidateHost || hostname.endsWith(`.${candidateHost}`);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
function inferNetworkIntent(requestUrl) {
|
|
909
|
+
const hostname = requestUrl?.hostname?.toLowerCase() || "";
|
|
910
|
+
const pathname = requestUrl?.pathname?.toLowerCase() || "";
|
|
911
|
+
if (pathname.includes("/api/v1/bom")) {
|
|
912
|
+
return "sbom-submit";
|
|
913
|
+
}
|
|
914
|
+
if (pathname.includes("/manifests/")) {
|
|
915
|
+
return "oci-manifest-access";
|
|
916
|
+
}
|
|
917
|
+
if (pathname.includes("/blobs/")) {
|
|
918
|
+
return "oci-layer-access";
|
|
919
|
+
}
|
|
920
|
+
if (
|
|
921
|
+
pathname.includes("license") ||
|
|
922
|
+
hostnameMatches(hostname, "spdx.org") ||
|
|
923
|
+
hostnameMatches(hostname, "opensource.org")
|
|
924
|
+
) {
|
|
925
|
+
return "license-fetch";
|
|
926
|
+
}
|
|
927
|
+
if (
|
|
928
|
+
hostnameMatches(hostname, "registry.npmjs.org") ||
|
|
929
|
+
hostnameMatches(hostname, "pypi.org") ||
|
|
930
|
+
hostnameMatches(hostname, "rubygems.org") ||
|
|
931
|
+
hostnameMatches(hostname, "repo.maven.apache.org") ||
|
|
932
|
+
hostnameMatches(hostname, "repo1.maven.org") ||
|
|
933
|
+
hostnameMatches(hostname, "crates.io") ||
|
|
934
|
+
hostnameMatches(hostname, "pub.dev") ||
|
|
935
|
+
hostnameMatches(hostname, "nuget.org")
|
|
936
|
+
) {
|
|
937
|
+
return "registry-lookup";
|
|
938
|
+
}
|
|
939
|
+
if (hostnameMatches(hostname, "github.com") && pathname.endsWith(".git")) {
|
|
940
|
+
return "git-fetch";
|
|
941
|
+
}
|
|
942
|
+
return "metadata-fetch";
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/** The shared got-compatible HTTP client for all outbound requests, enforcing dry-run, host-allow-list, and secure-mode policies via beforeRequest/afterResponse/beforeError hooks. */
|
|
946
|
+
export const cdxgenAgent = createHttpClient({
|
|
947
|
+
headers: {
|
|
948
|
+
"user-agent": `@CycloneDX/cdxgen ${CDXGEN_VERSION}`,
|
|
949
|
+
},
|
|
950
|
+
// Bound every request so an unresponsive host cannot hang a scan. Overridable
|
|
951
|
+
// via CDXGEN_HTTP_TIMEOUT_MS; individual calls may pass a smaller `timeout`.
|
|
952
|
+
timeout: getDefaultHttpTimeoutMs(),
|
|
953
|
+
retry: {
|
|
954
|
+
limit: 0,
|
|
955
|
+
},
|
|
956
|
+
followRedirect: !isSecureMode,
|
|
957
|
+
hooks: {
|
|
958
|
+
beforeRequest: [
|
|
959
|
+
(options) => {
|
|
960
|
+
const networkIntent =
|
|
961
|
+
options.context?.activityIntent || inferNetworkIntent(options.url);
|
|
962
|
+
const allowedHostsEnv = readEnvironmentVariable("CDXGEN_ALLOWED_HOSTS");
|
|
963
|
+
const hostAllowed = isAllowedHttpHost(
|
|
964
|
+
options.url.hostname,
|
|
965
|
+
allowedHostsEnv,
|
|
966
|
+
);
|
|
967
|
+
options.context = {
|
|
968
|
+
...options.context,
|
|
969
|
+
activityIntent: networkIntent,
|
|
970
|
+
activityTarget: options.url.toString(),
|
|
971
|
+
};
|
|
972
|
+
if (allowedHostsEnv) {
|
|
973
|
+
recordPolicyActivity(options.url.hostname, {
|
|
974
|
+
metadata: {
|
|
975
|
+
allowed: hostAllowed,
|
|
976
|
+
allowlist: allowedHostsEnv,
|
|
977
|
+
networkIntent,
|
|
978
|
+
policyType: "host-allowlist",
|
|
979
|
+
},
|
|
980
|
+
reason: `${hostAllowed ? "Allowed" : "Blocked"} host ${options.url.hostname} against CDXGEN_ALLOWED_HOSTS.`,
|
|
981
|
+
status: hostAllowed ? "completed" : "blocked",
|
|
982
|
+
traceDetail: "host-allowlist",
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
if (isDryRun) {
|
|
986
|
+
const error = createDryRunError(
|
|
987
|
+
"network",
|
|
988
|
+
options.url.toString(),
|
|
989
|
+
`Dry run mode blocks outbound network access (${networkIntent}).`,
|
|
990
|
+
);
|
|
991
|
+
recordActivity({
|
|
992
|
+
kind: "network",
|
|
993
|
+
networkIntent,
|
|
994
|
+
reason: error.message,
|
|
995
|
+
status: "blocked",
|
|
996
|
+
target: options.url.toString(),
|
|
997
|
+
});
|
|
998
|
+
options.context.activityBlocked = true;
|
|
999
|
+
throw error;
|
|
1000
|
+
}
|
|
1001
|
+
if (!hostAllowed) {
|
|
1002
|
+
console.log(
|
|
1003
|
+
`Access to the remote host '${options.url.hostname}' is not permitted.`,
|
|
1004
|
+
);
|
|
1005
|
+
recordActivity({
|
|
1006
|
+
kind: "network",
|
|
1007
|
+
networkIntent,
|
|
1008
|
+
reason: "The remote host is not permitted.",
|
|
1009
|
+
status: "blocked",
|
|
1010
|
+
target: options.url.toString(),
|
|
1011
|
+
});
|
|
1012
|
+
options.context.activityBlocked = true;
|
|
1013
|
+
throw createBlockedHostError(
|
|
1014
|
+
options.url.toString(),
|
|
1015
|
+
`The remote host '${options.url.hostname}' is not permitted by CDXGEN_ALLOWED_HOSTS.`,
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
// Only allow https protocol in secure mode
|
|
1019
|
+
if (isSecureMode && options.url.protocol !== "https:") {
|
|
1020
|
+
console.log(
|
|
1021
|
+
`Access to the remote host '${options.url.hostname}' is not permitted via the '${options.url.protocol}' protocol.`,
|
|
1022
|
+
);
|
|
1023
|
+
recordActivity({
|
|
1024
|
+
kind: "network",
|
|
1025
|
+
networkIntent,
|
|
1026
|
+
reason: `The '${options.url.protocol}' protocol is not permitted in secure mode.`,
|
|
1027
|
+
status: "blocked",
|
|
1028
|
+
target: options.url.toString(),
|
|
1029
|
+
});
|
|
1030
|
+
options.context.activityBlocked = true;
|
|
1031
|
+
throw createBlockedHostError(
|
|
1032
|
+
options.url.toString(),
|
|
1033
|
+
`The '${options.url.protocol}' protocol is not permitted in secure mode.`,
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
remoteHostsAccessed.add(options.url.hostname);
|
|
1037
|
+
traceLog("http", {
|
|
1038
|
+
protocol: options.url.protocol,
|
|
1039
|
+
pathname: options.url.pathname,
|
|
1040
|
+
host: options.url.host,
|
|
1041
|
+
});
|
|
1042
|
+
},
|
|
1043
|
+
],
|
|
1044
|
+
afterResponse: [
|
|
1045
|
+
(response) => {
|
|
1046
|
+
if (response.statusCode < 200 || response.statusCode >= 300) {
|
|
1047
|
+
return response;
|
|
1048
|
+
}
|
|
1049
|
+
const activityTarget =
|
|
1050
|
+
response.request.options.context?.activityTarget ||
|
|
1051
|
+
response.request.options.url?.toString() ||
|
|
1052
|
+
response.url;
|
|
1053
|
+
recordActivity({
|
|
1054
|
+
kind: "network",
|
|
1055
|
+
networkIntent: response.request.options.context?.activityIntent,
|
|
1056
|
+
status: "completed",
|
|
1057
|
+
target: activityTarget,
|
|
1058
|
+
});
|
|
1059
|
+
return response;
|
|
1060
|
+
},
|
|
1061
|
+
],
|
|
1062
|
+
beforeError: [
|
|
1063
|
+
(error) => {
|
|
1064
|
+
if (error.options?.context?.activityBlocked) {
|
|
1065
|
+
return error;
|
|
1066
|
+
}
|
|
1067
|
+
recordActivity({
|
|
1068
|
+
kind: "network",
|
|
1069
|
+
networkIntent: error.options?.context?.activityIntent,
|
|
1070
|
+
reason: error.message,
|
|
1071
|
+
status: "failed",
|
|
1072
|
+
target:
|
|
1073
|
+
error.options?.context?.activityTarget ||
|
|
1074
|
+
error.options?.url?.toString(),
|
|
1075
|
+
});
|
|
1076
|
+
return error;
|
|
1077
|
+
},
|
|
1078
|
+
],
|
|
1079
|
+
},
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
export {
|
|
1083
|
+
buildReadCountSuffix,
|
|
1084
|
+
classifyActivityPath,
|
|
1085
|
+
classifyDiscoveryPattern,
|
|
1086
|
+
recordFilesystemActivity,
|
|
1087
|
+
};
|