@cdxgen/cdxgen 13.0.1 → 13.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -16
- package/bin/audit.js +6 -0
- package/bin/cdxgen.js +141 -7
- package/bin/evinse.js +3 -1
- package/data/component-tags.json +8 -1
- package/data/crypto-oid.json +88 -12
- package/data/frameworks-list.json +86 -1
- package/data/remediations.json +1167 -0
- package/data/rules/ai-bom.yaml +78 -0
- package/data/rules/asar-archives.yaml +1 -1
- package/data/rules/build-fidelity.yaml +782 -0
- package/data/rules/cargo-rust.yaml +132 -0
- package/data/rules/mcp-servers.yaml +122 -0
- package/data/rules/package-integrity.yaml +13 -13
- package/lib/audit/index.js +48 -4
- package/lib/audit/scoring.js +2 -8
- package/lib/audit/targets.js +6 -1
- package/lib/cli/bomAssembly.js +32 -1
- package/lib/cli/cliOptions.js +94 -7
- package/lib/cli/index.js +268 -49
- package/lib/cli/jsBom.js +91 -5
- package/lib/cli/jvmBom.js +1515 -1314
- package/lib/cli/managedBom.js +249 -28
- package/lib/cli/nativeBom.js +986 -10
- package/lib/core/activity.js +120 -2
- package/lib/core/buildLedger.js +799 -0
- package/lib/core/deferredExit.js +141 -0
- package/lib/core/env.js +108 -2
- package/lib/core/fs.js +60 -0
- package/lib/core/logger.js +12 -99
- package/lib/core/severity.js +16 -0
- package/lib/core/syncFileWriter.js +106 -0
- package/lib/core/userAgent.js +151 -0
- package/lib/ecosystems/cargoCache.js +364 -0
- package/lib/ecosystems/caxa.js +13 -5
- package/lib/ecosystems/cppEvidence.js +40 -2
- package/lib/ecosystems/ecosystems.js +250 -91
- package/lib/ecosystems/golem.js +11 -1
- package/lib/ecosystems/gradleutils.js +498 -17
- package/lib/ecosystems/kosi.js +1256 -0
- package/lib/ecosystems/parsers-crystal.js +179 -0
- package/lib/ecosystems/parsers-dotnet.js +69 -39
- package/lib/ecosystems/parsers-elm.js +816 -0
- package/lib/ecosystems/parsers-gleam.js +1 -1
- package/lib/ecosystems/parsers-js.js +26 -0
- package/lib/ecosystems/parsers-julia.js +268 -0
- package/lib/ecosystems/parsers-jvm.js +9 -0
- package/lib/ecosystems/parsers-lua.js +218 -0
- package/lib/ecosystems/parsers-misc.js +188 -2
- package/lib/ecosystems/parsers-nim.js +221 -0
- package/lib/ecosystems/parsers-opam.js +180 -0
- package/lib/ecosystems/parsers-perl.js +277 -0
- package/lib/ecosystems/parsers-python.js +172 -36
- package/lib/ecosystems/parsers-r.js +148 -0
- package/lib/ecosystems/parsers-rebar.js +411 -0
- package/lib/ecosystems/parsers-rust.js +944 -19
- package/lib/ecosystems/parsers-spack.js +204 -0
- package/lib/ecosystems/parsers-stack.js +264 -0
- package/lib/ecosystems/parsers-terraform.js +194 -0
- package/lib/ecosystems/pypiClassifiers.js +326 -0
- package/lib/ecosystems/pythonutils.js +49 -1
- package/lib/ecosystems/rubyutils.js +13 -0
- package/lib/ecosystems/rusi.js +126 -6
- package/lib/evinser/evinser.js +141 -13
- package/lib/helpers/agenticToolutils.js +925 -0
- package/lib/helpers/remote/dependency-track.js +81 -14
- package/lib/inventory/agentFormulationParser.js +57 -4
- package/lib/inventory/aiCollector.js +504 -10
- package/lib/inventory/aiInventory.js +12 -0
- package/lib/inventory/analyzer.js +488 -30
- package/lib/inventory/astWorker.js +6 -0
- package/lib/inventory/auditCategories.js +17 -0
- package/lib/inventory/cbomutils.js +30 -0
- package/lib/inventory/cdxrs.js +7 -2
- package/lib/inventory/communityAiConfigParser.js +215 -2
- package/lib/inventory/depsUtils.js +72 -0
- package/lib/inventory/dosai.js +508 -22
- package/lib/inventory/envcontext.js +215 -24
- package/lib/inventory/evidenceUtils.js +13 -0
- package/lib/inventory/fetchBatch.js +131 -2
- package/lib/inventory/fetchRate.js +74 -11
- package/lib/inventory/forgeEnricher.js +3 -2
- package/lib/inventory/jvmToolEnv.js +594 -0
- package/lib/inventory/mcpConfigParser.js +166 -2
- package/lib/inventory/mcpDiscovery.js +11 -0
- package/lib/inventory/mcpServerManifest.js +389 -0
- package/lib/inventory/mcpbBundle.js +419 -0
- package/lib/inventory/osinfo.js +1 -0
- package/lib/inventory/plugins.js +3 -0
- package/lib/inventory/protobom.js +54 -88
- package/lib/inventory/protobomLoader.js +4 -0
- package/lib/inventory/rustFormulationParser.js +1 -1
- package/lib/inventory/source.js +10 -4
- package/lib/inventory/stylePackageRefs.js +41 -0
- package/lib/inventory/svelteUtils.js +524 -0
- package/lib/inventory/toolRequirements.js +903 -0
- package/lib/managers/binary.js +24 -0
- package/lib/managers/docker.js +26 -5
- package/lib/parsers/huggingfaceUtils.js +15 -7
- package/lib/parsers/onnx.js +294 -0
- package/lib/parsers/safetensors.js +114 -0
- package/lib/server/server.js +1 -1
- package/lib/stages/postgen/annotationBuilder.js +97 -0
- package/lib/stages/postgen/auditBom.js +76 -79
- package/lib/stages/postgen/introspection/annotate.js +320 -0
- package/lib/stages/postgen/introspection/commandFacts.js +293 -0
- package/lib/stages/postgen/introspection/emit.js +192 -0
- package/lib/stages/postgen/introspection/formulationEvidence.js +427 -0
- package/lib/stages/postgen/introspection/markers.js +250 -0
- package/lib/stages/postgen/introspection/reflect.js +1214 -0
- package/lib/stages/postgen/introspection/report.js +1208 -0
- package/lib/stages/postgen/introspection/score.js +1067 -0
- package/lib/stages/postgen/introspection/shapeCommand.js +304 -0
- package/lib/stages/postgen/parentEdge.js +156 -0
- package/lib/stages/postgen/postgen.js +284 -3
- package/lib/stages/postgen/ruleEngine.js +17 -0
- package/lib/stages/pregen/envAudit.js +42 -2
- package/lib/stages/pregen/pregen.js +1171 -6
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +462 -0
- package/lib/validator/bomValidator.js +11 -2
- package/package.json +26 -26
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/audit/scoring.d.ts +2 -8
- package/types/lib/audit/scoring.d.ts.map +1 -1
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +2 -1
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +10 -2
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jsBom.d.ts +23 -0
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts +33 -0
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts +88 -8
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/activity.d.ts.map +1 -1
- package/types/lib/core/buildLedger.d.ts +272 -0
- package/types/lib/core/buildLedger.d.ts.map +1 -0
- package/types/lib/core/deferredExit.d.ts +84 -0
- package/types/lib/core/deferredExit.d.ts.map +1 -0
- package/types/lib/core/env.d.ts +43 -1
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts +21 -0
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/logger.d.ts +2 -11
- package/types/lib/core/logger.d.ts.map +1 -1
- package/types/lib/core/severity.d.ts +11 -0
- package/types/lib/core/severity.d.ts.map +1 -0
- package/types/lib/core/syncFileWriter.d.ts +33 -0
- package/types/lib/core/syncFileWriter.d.ts.map +1 -0
- package/types/lib/core/userAgent.d.ts +56 -0
- package/types/lib/core/userAgent.d.ts.map +1 -0
- package/types/lib/ecosystems/cargoCache.d.ts +75 -0
- package/types/lib/ecosystems/cargoCache.d.ts.map +1 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -1
- package/types/lib/ecosystems/cppEvidence.d.ts +1 -1
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts +15 -1
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +53 -0
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts +73 -0
- package/types/lib/ecosystems/kosi.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-crystal.d.ts +27 -0
- package/types/lib/ecosystems/parsers-crystal.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts +19 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-elm.d.ts +79 -0
- package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-julia.d.ts +57 -0
- package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-lua.d.ts +50 -0
- package/types/lib/ecosystems/parsers-lua.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-misc.d.ts +23 -0
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-nim.d.ts +43 -0
- package/types/lib/ecosystems/parsers-nim.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-opam.d.ts +31 -0
- package/types/lib/ecosystems/parsers-opam.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-perl.d.ts +36 -0
- package/types/lib/ecosystems/parsers-perl.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-r.d.ts +35 -0
- package/types/lib/ecosystems/parsers-r.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rebar.d.ts +42 -0
- package/types/lib/ecosystems/parsers-rebar.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rust.d.ts +199 -0
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-spack.d.ts +33 -0
- package/types/lib/ecosystems/parsers-spack.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-stack.d.ts +35 -0
- package/types/lib/ecosystems/parsers-stack.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-terraform.d.ts +34 -0
- package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -0
- package/types/lib/ecosystems/pypiClassifiers.d.ts +80 -0
- package/types/lib/ecosystems/pypiClassifiers.d.ts.map +1 -0
- package/types/lib/ecosystems/pythonutils.d.ts +21 -1
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +34 -1
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/agenticToolutils.d.ts +87 -0
- package/types/lib/helpers/agenticToolutils.d.ts.map +1 -0
- package/types/lib/helpers/remote/dependency-track.d.ts +45 -4
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
- package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/aiInventory.d.ts.map +1 -1
- package/types/lib/inventory/analyzer.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +12 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/cbomutils.d.ts.map +1 -1
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/depsUtils.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +43 -0
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/fetchBatch.d.ts +43 -0
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/fetchRate.d.ts +9 -6
- package/types/lib/inventory/fetchRate.d.ts.map +1 -1
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
- package/types/lib/inventory/jvmToolEnv.d.ts +190 -0
- package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -1
- package/types/lib/inventory/mcpServerManifest.d.ts +19 -0
- package/types/lib/inventory/mcpServerManifest.d.ts.map +1 -0
- package/types/lib/inventory/mcpbBundle.d.ts +19 -0
- package/types/lib/inventory/mcpbBundle.d.ts.map +1 -0
- package/types/lib/inventory/osinfo.d.ts.map +1 -1
- package/types/lib/inventory/plugins.d.ts.map +1 -1
- package/types/lib/inventory/protobom.d.ts +18 -13
- package/types/lib/inventory/protobom.d.ts.map +1 -1
- package/types/lib/inventory/protobomLoader.d.ts.map +1 -1
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/stylePackageRefs.d.ts +17 -0
- package/types/lib/inventory/stylePackageRefs.d.ts.map +1 -0
- package/types/lib/inventory/svelteUtils.d.ts +124 -0
- package/types/lib/inventory/svelteUtils.d.ts.map +1 -0
- package/types/lib/inventory/toolRequirements.d.ts +216 -0
- package/types/lib/inventory/toolRequirements.d.ts.map +1 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/parsers/huggingfaceUtils.d.ts +8 -1
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
- package/types/lib/parsers/onnx.d.ts +28 -0
- package/types/lib/parsers/onnx.d.ts.map +1 -0
- package/types/lib/parsers/safetensors.d.ts +22 -0
- package/types/lib/parsers/safetensors.d.ts.map +1 -0
- package/types/lib/stages/postgen/annotationBuilder.d.ts +53 -0
- package/types/lib/stages/postgen/annotationBuilder.d.ts.map +1 -0
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
- package/types/lib/stages/postgen/introspection/annotate.d.ts +81 -0
- package/types/lib/stages/postgen/introspection/annotate.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/commandFacts.d.ts +32 -0
- package/types/lib/stages/postgen/introspection/commandFacts.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/emit.d.ts +71 -0
- package/types/lib/stages/postgen/introspection/emit.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/formulationEvidence.d.ts +154 -0
- package/types/lib/stages/postgen/introspection/formulationEvidence.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/markers.d.ts +58 -0
- package/types/lib/stages/postgen/introspection/markers.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/reflect.d.ts +77 -0
- package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/report.d.ts +85 -0
- package/types/lib/stages/postgen/introspection/report.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/score.d.ts +149 -0
- package/types/lib/stages/postgen/introspection/score.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/shapeCommand.d.ts +79 -0
- package/types/lib/stages/postgen/introspection/shapeCommand.d.ts.map +1 -0
- package/types/lib/stages/postgen/parentEdge.d.ts +35 -0
- package/types/lib/stages/postgen/parentEdge.d.ts.map +1 -0
- package/types/lib/stages/postgen/postgen.d.ts +35 -2
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
- package/types/lib/stages/pregen/pregen.d.ts +131 -0
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
|
@@ -66,11 +66,13 @@ import {
|
|
|
66
66
|
prefetchEnabled,
|
|
67
67
|
prefetchedResponse,
|
|
68
68
|
prefetchJson,
|
|
69
|
+
withHostRateLimit,
|
|
69
70
|
} from "../inventory/fetchBatch.js";
|
|
70
71
|
import {
|
|
71
72
|
applyPurl,
|
|
72
73
|
encodeForPurl,
|
|
73
74
|
genericPurl,
|
|
75
|
+
nugetPurl,
|
|
74
76
|
pypiPurl,
|
|
75
77
|
} from "../inventory/purl.js";
|
|
76
78
|
import {
|
|
@@ -80,6 +82,14 @@ import {
|
|
|
80
82
|
} from "../inventory/spdx.js";
|
|
81
83
|
import { extractLicenseText, extractRepoUrl } from "../parsers/htmlExtract.js";
|
|
82
84
|
import { xml2js } from "../parsers/xml.js";
|
|
85
|
+
import {
|
|
86
|
+
localCargoMetadataEnabled,
|
|
87
|
+
readCargoCacheMetadata,
|
|
88
|
+
} from "./cargoCache.js";
|
|
89
|
+
import {
|
|
90
|
+
applyPypiClassifierMetadata,
|
|
91
|
+
applyPypiModuleNames,
|
|
92
|
+
} from "./pypiClassifiers.js";
|
|
83
93
|
import {
|
|
84
94
|
collectCargoRegistryProvenanceProperties,
|
|
85
95
|
collectNpmRegistryProvenanceProperties,
|
|
@@ -810,11 +820,13 @@ export async function fetchPomXml({ urlPrefix, group, name, version }) {
|
|
|
810
820
|
// A direct POM may have been prefetched by getMvnMetadata's batch round.
|
|
811
821
|
// Parent POMs (fetched from inside fetchPomXmlAsJson) are not prefetched
|
|
812
822
|
// because their URL depends on the direct POM's content, so they fall
|
|
813
|
-
// through to the serial request
|
|
823
|
+
// through to the serial request. That fallback still reaches Maven Central
|
|
824
|
+
// and still counts against the same budget as the batch round, so it queues
|
|
825
|
+
// behind the same per-host gate rather than a second, ungoverned one.
|
|
814
826
|
try {
|
|
815
827
|
const res =
|
|
816
828
|
prefetchedResponse(prefetchedPoms, fullUrl) ||
|
|
817
|
-
(await cdxgenAgent.get(fullUrl));
|
|
829
|
+
(await withHostRateLimit(fullUrl, () => cdxgenAgent.get(fullUrl)));
|
|
818
830
|
return res.body;
|
|
819
831
|
} catch (_err) {
|
|
820
832
|
return undefined;
|
|
@@ -950,6 +962,10 @@ export async function getPyMetadata(pkgList, fetchDepsInfo) {
|
|
|
950
962
|
continue;
|
|
951
963
|
}
|
|
952
964
|
try {
|
|
965
|
+
// Module names are derived from the distribution name and the curated alias
|
|
966
|
+
// map, so they are available without a registry round trip and are attached
|
|
967
|
+
// before the skip below rather than after it.
|
|
968
|
+
applyPypiModuleNames(p);
|
|
953
969
|
// If the package name has a url or already includes license and version skip it
|
|
954
970
|
if (p.name.includes("https") || (p.license && p.version)) {
|
|
955
971
|
cdepList.push(p);
|
|
@@ -1011,6 +1027,7 @@ export async function getPyMetadata(pkgList, fetchDepsInfo) {
|
|
|
1011
1027
|
}
|
|
1012
1028
|
}
|
|
1013
1029
|
}
|
|
1030
|
+
applyPypiClassifierMetadata(p, body.info.classifiers);
|
|
1014
1031
|
}
|
|
1015
1032
|
if (body.info.license) {
|
|
1016
1033
|
const licenseId = findLicenseId(body.info.license);
|
|
@@ -1783,24 +1800,61 @@ function getGoPkgFullName(group, name) {
|
|
|
1783
1800
|
/**
|
|
1784
1801
|
* Method to retrieve metadata for rust packages by querying crates
|
|
1785
1802
|
*
|
|
1803
|
+
* The local Cargo registry is consulted first, because crates.io's crawler
|
|
1804
|
+
* policy allows one request per second and a populated `~/.cargo` already
|
|
1805
|
+
* holds the license, description, repository, checksum and yanked flag for
|
|
1806
|
+
* every crate the build compiled.
|
|
1807
|
+
*
|
|
1808
|
+
* What it does not hold is publisher identity, so a caller that needs the
|
|
1809
|
+
* publisher-drift and release-cadence signals — the predictive audit does —
|
|
1810
|
+
* passes `preferLocalCache: false` and takes the slower registry path.
|
|
1811
|
+
*
|
|
1786
1812
|
* @param {Array} pkgList Package list
|
|
1813
|
+
* @param {Object} [options] Options
|
|
1814
|
+
* @param {boolean} [options.preferLocalCache=true] Answer from the local Cargo
|
|
1815
|
+
* registry where it can, and query crates.io only for the rest.
|
|
1787
1816
|
*/
|
|
1788
|
-
export async function getCratesMetadata(pkgList) {
|
|
1817
|
+
export async function getCratesMetadata(pkgList, options = {}) {
|
|
1789
1818
|
const CRATES_URL =
|
|
1790
1819
|
readEnvironmentVariable("RUST_CRATES_URL") ||
|
|
1791
1820
|
"https://crates.io/api/v1/crates/";
|
|
1792
1821
|
const cdepList = [];
|
|
1822
|
+
// The local Cargo registry answers first. crates.io allows one request per
|
|
1823
|
+
// second, so a populated ~/.cargo turns minutes of waiting into a few file
|
|
1824
|
+
// reads; only the crates it cannot account for reach the network.
|
|
1825
|
+
const servedLocally = new Set();
|
|
1826
|
+
const preferLocalCache = options.preferLocalCache !== false;
|
|
1827
|
+
if (preferLocalCache && localCargoMetadataEnabled()) {
|
|
1828
|
+
for (const p of pkgList) {
|
|
1829
|
+
if (!p?.name || !p?.version || p.version === "workspace") {
|
|
1830
|
+
continue;
|
|
1831
|
+
}
|
|
1832
|
+
if (applyCargoCacheMetadata(p)) {
|
|
1833
|
+
servedLocally.add(p);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
if (DEBUG_MODE && servedLocally.size) {
|
|
1837
|
+
console.log(
|
|
1838
|
+
`Resolved ${servedLocally.size} of ${pkgList.length} crate(s) from the local Cargo registry.`,
|
|
1839
|
+
);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
const needsRegistry = pkgList.filter(
|
|
1843
|
+
(p) =>
|
|
1844
|
+
p?.name &&
|
|
1845
|
+
p?.version &&
|
|
1846
|
+
p.version !== "workspace" &&
|
|
1847
|
+
!servedLocally.has(p),
|
|
1848
|
+
);
|
|
1793
1849
|
// Two URLs per crate — the crate document and its owners — fetched for the
|
|
1794
1850
|
// whole list at once. The `workspace` guard below is mirrored here so the
|
|
1795
1851
|
// batch does not request anything the loop would have skipped.
|
|
1796
1852
|
const prefetched = await prefetchJson(
|
|
1797
1853
|
prefetchEnabled()
|
|
1798
|
-
?
|
|
1799
|
-
|
|
1800
|
-
.
|
|
1801
|
-
|
|
1802
|
-
{ url: `${CRATES_URL + p.name}/owners` },
|
|
1803
|
-
])
|
|
1854
|
+
? needsRegistry.flatMap((p) => [
|
|
1855
|
+
{ url: CRATES_URL + p.name },
|
|
1856
|
+
{ url: `${CRATES_URL + p.name}/owners` },
|
|
1857
|
+
])
|
|
1804
1858
|
: [],
|
|
1805
1859
|
);
|
|
1806
1860
|
for (const p of pkgList) {
|
|
@@ -1809,23 +1863,35 @@ export async function getCratesMetadata(pkgList) {
|
|
|
1809
1863
|
cdepList.push(p);
|
|
1810
1864
|
continue;
|
|
1811
1865
|
}
|
|
1866
|
+
if (servedLocally.has(p)) {
|
|
1867
|
+
cdepList.push(p);
|
|
1868
|
+
continue;
|
|
1869
|
+
}
|
|
1812
1870
|
if (DEBUG_MODE) {
|
|
1813
1871
|
console.log(`Querying crates.io for ${p.name}@${p.version}`);
|
|
1814
1872
|
}
|
|
1815
1873
|
const crateUrl = CRATES_URL + p.name;
|
|
1874
|
+
// A prefetch miss falls back to a direct request, which must queue
|
|
1875
|
+
// behind the same crates.io gate the batch pool uses: the registry
|
|
1876
|
+
// allows one request per second and does not care which code path in
|
|
1877
|
+
// this process issued it.
|
|
1816
1878
|
const res =
|
|
1817
1879
|
prefetchedResponse(prefetched, crateUrl) ||
|
|
1818
|
-
(await
|
|
1819
|
-
|
|
1820
|
-
|
|
1880
|
+
(await withHostRateLimit(crateUrl, () =>
|
|
1881
|
+
cdxgenAgent.get(crateUrl, {
|
|
1882
|
+
responseType: "json",
|
|
1883
|
+
}),
|
|
1884
|
+
));
|
|
1821
1885
|
let ownersRes;
|
|
1822
1886
|
try {
|
|
1823
1887
|
const ownersUrl = `${crateUrl}/owners`;
|
|
1824
1888
|
ownersRes =
|
|
1825
1889
|
prefetchedResponse(prefetched, ownersUrl) ||
|
|
1826
|
-
(await
|
|
1827
|
-
|
|
1828
|
-
|
|
1890
|
+
(await withHostRateLimit(ownersUrl, () =>
|
|
1891
|
+
cdxgenAgent.get(ownersUrl, {
|
|
1892
|
+
responseType: "json",
|
|
1893
|
+
}),
|
|
1894
|
+
));
|
|
1829
1895
|
} catch (_err) {
|
|
1830
1896
|
ownersRes = undefined;
|
|
1831
1897
|
}
|
|
@@ -1895,6 +1961,86 @@ export async function getCratesMetadata(pkgList) {
|
|
|
1895
1961
|
return cdepList;
|
|
1896
1962
|
}
|
|
1897
1963
|
|
|
1964
|
+
/**
|
|
1965
|
+
* Apply the local Cargo registry's view of a crate to its component.
|
|
1966
|
+
*
|
|
1967
|
+
* Returns whether the component is complete enough to skip crates.io. The bar
|
|
1968
|
+
* is the license: `getCratesMetadata` runs only under `FETCH_LICENSE`, so a
|
|
1969
|
+
* crate whose license the local registry cannot name has not answered the
|
|
1970
|
+
* question that was asked and still needs the network. That happens when the
|
|
1971
|
+
* index knows a version but Cargo never extracted its sources — a crate the
|
|
1972
|
+
* lockfile pins but the build never compiled.
|
|
1973
|
+
*
|
|
1974
|
+
* Publisher identity has no local equivalent, so a component served from here
|
|
1975
|
+
* carries the publish time and yanked flag but none of the publisher-drift
|
|
1976
|
+
* properties; `cdx:cargo:metadataSource` records which it was.
|
|
1977
|
+
*
|
|
1978
|
+
* @param {Object} p Package component to enrich in place.
|
|
1979
|
+
* @returns {boolean} true when crates.io can be skipped for this crate.
|
|
1980
|
+
*/
|
|
1981
|
+
function applyCargoCacheMetadata(p) {
|
|
1982
|
+
const local = readCargoCacheMetadata(p.name, p.version);
|
|
1983
|
+
if (!local?.license) {
|
|
1984
|
+
return false;
|
|
1985
|
+
}
|
|
1986
|
+
p.license = local.license;
|
|
1987
|
+
if (local.description) {
|
|
1988
|
+
p.description = local.description;
|
|
1989
|
+
}
|
|
1990
|
+
if (local.repository) {
|
|
1991
|
+
p.repository = { url: local.repository };
|
|
1992
|
+
}
|
|
1993
|
+
if (local.homepage && local.homepage !== local.repository) {
|
|
1994
|
+
p.homepage = { url: local.homepage };
|
|
1995
|
+
}
|
|
1996
|
+
if (!p._integrity && local.checksum) {
|
|
1997
|
+
p._integrity = normalizeCargoIntegrity(local.checksum);
|
|
1998
|
+
}
|
|
1999
|
+
if (!p.properties) {
|
|
2000
|
+
p.properties = [];
|
|
2001
|
+
}
|
|
2002
|
+
p.properties.push({
|
|
2003
|
+
name: "cdx:cargo:metadataSource",
|
|
2004
|
+
value: "local-registry",
|
|
2005
|
+
});
|
|
2006
|
+
if (local.rustVersion) {
|
|
2007
|
+
p.properties.push({
|
|
2008
|
+
name: "cdx:cargo:rust_version",
|
|
2009
|
+
value: local.rustVersion,
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
2012
|
+
if (local.latestVersion) {
|
|
2013
|
+
p.properties.push({
|
|
2014
|
+
name: "cdx:cargo:latest_version",
|
|
2015
|
+
value: local.latestVersion,
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
if (typeof local.yanked === "boolean") {
|
|
2019
|
+
p.properties.push({
|
|
2020
|
+
name: "cdx:cargo:yanked",
|
|
2021
|
+
value: String(local.yanked),
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
if (local.publishTime) {
|
|
2025
|
+
p.properties.push({
|
|
2026
|
+
name: "cdx:cargo:publishTime",
|
|
2027
|
+
value: local.publishTime,
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
if (local.features && Object.keys(local.features).length) {
|
|
2031
|
+
p.properties.push({
|
|
2032
|
+
name: "cdx:cargo:features",
|
|
2033
|
+
value: JSON.stringify(local.features),
|
|
2034
|
+
});
|
|
2035
|
+
}
|
|
2036
|
+
// The download path is a documented, stable URL shape rather than something
|
|
2037
|
+
// the API had to tell us, so it costs no request to state it.
|
|
2038
|
+
p.distribution = {
|
|
2039
|
+
url: `https://crates.io/api/v1/crates/${p.name}/${p.version}/download`,
|
|
2040
|
+
};
|
|
2041
|
+
return true;
|
|
2042
|
+
}
|
|
2043
|
+
|
|
1898
2044
|
/**
|
|
1899
2045
|
* Method to retrieve metadata for dart packages by querying pub.dev
|
|
1900
2046
|
*
|
|
@@ -2159,17 +2305,23 @@ export async function extractJarArchive(jarFile, tempDir, jarNSMapping = {}) {
|
|
|
2159
2305
|
try {
|
|
2160
2306
|
const sha = await checksumFile("sha1", jf);
|
|
2161
2307
|
const searchurl = `https://central.sonatype.com/solrsearch/select?q=1:%22${sha}%22&rows=20&wt=json`;
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2308
|
+
// One Solr query per unidentified jar, against Central's origin
|
|
2309
|
+
// rather than its CDN. A directory of jars issues these back to
|
|
2310
|
+
// back, so they go through the same per-host gate the batch pool
|
|
2311
|
+
// uses (500 ms, serial) instead of a second, ungoverned path.
|
|
2312
|
+
const res = await withHostRateLimit(searchurl, () =>
|
|
2313
|
+
cdxgenAgent.get(searchurl, {
|
|
2314
|
+
responseType: "json",
|
|
2315
|
+
timeout: {
|
|
2316
|
+
lookup: 1000,
|
|
2317
|
+
connect: 5000,
|
|
2318
|
+
secureConnect: 5000,
|
|
2319
|
+
socket: 1000,
|
|
2320
|
+
send: 10000,
|
|
2321
|
+
response: 1000,
|
|
2322
|
+
},
|
|
2323
|
+
}),
|
|
2324
|
+
);
|
|
2173
2325
|
const data = res?.body ? res.body["response"] : undefined;
|
|
2174
2326
|
if (data && data["numFound"] === 1) {
|
|
2175
2327
|
const jarInfo = data["docs"][0];
|
|
@@ -2471,6 +2623,12 @@ async function unresolvedJarComponents(unresolvedJars, jarFile, tempDir) {
|
|
|
2471
2623
|
return components;
|
|
2472
2624
|
}
|
|
2473
2625
|
|
|
2626
|
+
/**
|
|
2627
|
+
* Property recording the NuGet release a versionless component's metadata was
|
|
2628
|
+
* read from, so the description and licence in the output can be traced.
|
|
2629
|
+
*/
|
|
2630
|
+
const METADATA_VERSION_PROP = "cdx:nuget:metadata_version";
|
|
2631
|
+
|
|
2474
2632
|
async function getNugetUrl() {
|
|
2475
2633
|
const req = "https://api.nuget.org/v3/index.json";
|
|
2476
2634
|
const res = await cdxgenAgent.get(req, {
|
|
@@ -2546,60 +2704,46 @@ async function queryNuget(p, NUGET_URL) {
|
|
|
2546
2704
|
if (!items?.[0]) {
|
|
2547
2705
|
return [np, newBody, body];
|
|
2548
2706
|
}
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2707
|
+
// A component that states no version at all is not the same as one carrying a
|
|
2708
|
+
// `latest` or `0.0.0` placeholder. The placeholder asks to be replaced, so the
|
|
2709
|
+
// registry's newest release becomes the component's version. A missing version
|
|
2710
|
+
// means the manifest never said which release is in use - a `<Reference>` to an
|
|
2711
|
+
// assembly is the usual source - and the newest release is then only a key for
|
|
2712
|
+
// looking metadata up, never a version to write back. See #4359.
|
|
2713
|
+
const versionStated = p.version && !["0.0.0", "latest"].includes(p.version);
|
|
2714
|
+
let lookupVersion = p.version;
|
|
2715
|
+
if (!versionStated) {
|
|
2716
|
+
lookupVersion = setLatestVersion(items[items.length - 1].upper);
|
|
2717
|
+
np.version = p.version ? lookupVersion : undefined;
|
|
2718
|
+
np.metadataVersion = lookupVersion;
|
|
2719
|
+
}
|
|
2720
|
+
if (lookupVersion) {
|
|
2554
2721
|
for (const item of items) {
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
res = await cdxgenAgent.get(item["@id"], { responseType: "json" });
|
|
2566
|
-
for (const i of res.body.items.reverse()) {
|
|
2567
|
-
if (
|
|
2568
|
-
i.catalogEntry &&
|
|
2569
|
-
i.catalogEntry.version === coerceUp(np.version)
|
|
2570
|
-
) {
|
|
2571
|
-
newBody.push(i);
|
|
2572
|
-
return [np, newBody];
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
}
|
|
2722
|
+
const lower = compare(
|
|
2723
|
+
coerce(item.lower, { loose: true }),
|
|
2724
|
+
coerce(lookupVersion, { loose: true }),
|
|
2725
|
+
);
|
|
2726
|
+
const upper = compare(
|
|
2727
|
+
coerce(item.upper, { loose: true }),
|
|
2728
|
+
coerce(lookupVersion, { loose: true }),
|
|
2729
|
+
);
|
|
2730
|
+
if (lower === 1 || upper === -1) {
|
|
2731
|
+
continue;
|
|
2576
2732
|
}
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
for (const
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
)
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
coerce(np.version, { loose: true }),
|
|
2592
|
-
);
|
|
2593
|
-
if (lower !== 1 && upper !== -1) {
|
|
2594
|
-
for (const i of item.items.reverse()) {
|
|
2595
|
-
if (
|
|
2596
|
-
i.catalogEntry &&
|
|
2597
|
-
i.catalogEntry.version === coerceUp(np.version)
|
|
2598
|
-
) {
|
|
2599
|
-
newBody.push(i);
|
|
2600
|
-
return [np, newBody];
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2733
|
+
// The registration index either inlines the leaves of each page or points
|
|
2734
|
+
// at a page that must be fetched.
|
|
2735
|
+
let leaves = item.items;
|
|
2736
|
+
if (!leaves) {
|
|
2737
|
+
res = await cdxgenAgent.get(item["@id"], { responseType: "json" });
|
|
2738
|
+
leaves = res.body.items;
|
|
2739
|
+
}
|
|
2740
|
+
for (const i of leaves.reverse()) {
|
|
2741
|
+
if (
|
|
2742
|
+
i.catalogEntry &&
|
|
2743
|
+
i.catalogEntry.version === coerceUp(lookupVersion)
|
|
2744
|
+
) {
|
|
2745
|
+
newBody.push(i);
|
|
2746
|
+
return [np, newBody];
|
|
2603
2747
|
}
|
|
2604
2748
|
}
|
|
2605
2749
|
}
|
|
@@ -2664,25 +2808,36 @@ export async function getNugetMetadata(pkgList, dependencies = undefined) {
|
|
|
2664
2808
|
[np, newBody] = await queryNuget(p, NUGET_URL);
|
|
2665
2809
|
if (p.version !== np.version) {
|
|
2666
2810
|
const oldRef = p["bom-ref"];
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
namespace: "" || null,
|
|
2671
|
-
name: np.name,
|
|
2672
|
-
version: np.version || null,
|
|
2673
|
-
}),
|
|
2674
|
-
);
|
|
2675
|
-
depRepList[oldRef] = p["bom-ref"];
|
|
2811
|
+
// The purl is rebuilt alongside the bom-ref. Leaving it behind let a
|
|
2812
|
+
// component state one version in `version` and another - or none - in
|
|
2813
|
+
// its purl, which is what a scanner range matches on. See #4359.
|
|
2676
2814
|
p.version = np.version;
|
|
2815
|
+
applyPurl(p, nugetPurl(np.name, np.version));
|
|
2816
|
+
if (oldRef && p["bom-ref"] !== oldRef) {
|
|
2817
|
+
depRepList[oldRef] = p["bom-ref"];
|
|
2818
|
+
}
|
|
2677
2819
|
}
|
|
2678
2820
|
if (newBody && newBody.length > 0) {
|
|
2679
2821
|
body = newBody[0];
|
|
2680
2822
|
}
|
|
2681
2823
|
if (body) {
|
|
2682
2824
|
metadata_cache[cacheKey] = body;
|
|
2683
|
-
//
|
|
2684
|
-
|
|
2685
|
-
|
|
2825
|
+
// The component states no version, so the description and licence
|
|
2826
|
+
// below were read from whichever release the lookup fell back to.
|
|
2827
|
+
// That release is recorded rather than adopted as the version: a
|
|
2828
|
+
// version cdxgen chose is not a version the project declared.
|
|
2829
|
+
if (!p.version && np.metadataVersion) {
|
|
2830
|
+
p.properties = p.properties || [];
|
|
2831
|
+
if (
|
|
2832
|
+
!p.properties.some(
|
|
2833
|
+
(prop) => prop.name === METADATA_VERSION_PROP,
|
|
2834
|
+
)
|
|
2835
|
+
) {
|
|
2836
|
+
p.properties.push({
|
|
2837
|
+
name: METADATA_VERSION_PROP,
|
|
2838
|
+
value: np.metadataVersion,
|
|
2839
|
+
});
|
|
2840
|
+
}
|
|
2686
2841
|
}
|
|
2687
2842
|
p.description = body.catalogEntry.description;
|
|
2688
2843
|
if (body.catalogEntry.authors) {
|
|
@@ -2711,8 +2866,12 @@ export async function getNugetMetadata(pkgList, dependencies = undefined) {
|
|
|
2711
2866
|
}
|
|
2712
2867
|
if (body.catalogEntry.projectUrl) {
|
|
2713
2868
|
p.repository = { url: body.catalogEntry.projectUrl };
|
|
2869
|
+
// A versionless component gets the package's landing page. Pasting
|
|
2870
|
+
// an undefined version into the path produced a 404 link.
|
|
2714
2871
|
p.homepage = {
|
|
2715
|
-
url:
|
|
2872
|
+
url: p.version
|
|
2873
|
+
? `https://www.nuget.org/packages/${p.name}/${p.version}/`
|
|
2874
|
+
: `https://www.nuget.org/packages/${p.name}/`,
|
|
2716
2875
|
};
|
|
2717
2876
|
if (
|
|
2718
2877
|
(!p.license || typeof p.license === "string") &&
|
package/lib/ecosystems/golem.js
CHANGED
|
@@ -1360,11 +1360,21 @@ function normalizedGolemDataFlowCallGraphMode(options = {}) {
|
|
|
1360
1360
|
return callgraphMode;
|
|
1361
1361
|
}
|
|
1362
1362
|
|
|
1363
|
+
function availableCpuCount() {
|
|
1364
|
+
try {
|
|
1365
|
+
return cpus()?.length || 1;
|
|
1366
|
+
} catch {
|
|
1367
|
+
// Deno denies the probe without --allow-sys=cpus; a worker-count hint
|
|
1368
|
+
// must not abort the analysis, so fall back to a single worker.
|
|
1369
|
+
return 1;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1363
1373
|
function appendGolemDataFlowArgs(args, dataFlowMode, options = {}) {
|
|
1364
1374
|
if (dataFlowMode === "none") {
|
|
1365
1375
|
return;
|
|
1366
1376
|
}
|
|
1367
|
-
const cpuCount =
|
|
1377
|
+
const cpuCount = availableCpuCount();
|
|
1368
1378
|
const performanceWorkerCount = Math.max(1, Math.min(cpuCount, 4));
|
|
1369
1379
|
const dataFlowCallgraph = normalizedGolemDataFlowCallGraphMode(options);
|
|
1370
1380
|
const dataFlowPacks =
|