@cdxgen/cdxgen 13.1.0 → 13.3.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 +32 -15
- package/bin/cdxgen.js +243 -122
- package/bin/evinse.js +7 -0
- package/bin/sign.js +88 -14
- package/bin/tracebom.js +64 -4
- package/bin/validate.js +29 -7
- package/bin/verify.js +79 -39
- package/data/crypto-oid.json +88 -12
- package/data/remediations.json +47 -0
- package/data/rules/ai-bom.yaml +78 -0
- package/data/rules/cargo-rust.yaml +132 -0
- package/data/rules/mcp-servers.yaml +122 -0
- package/lib/audit/targets.js +6 -1
- package/lib/cli/bomAssembly.js +117 -15
- package/lib/cli/cliOptions.js +93 -1
- package/lib/cli/index.js +235 -5
- package/lib/cli/jsBom.js +108 -26
- package/lib/cli/jvmBom.js +68 -12
- package/lib/cli/managedBom.js +264 -41
- package/lib/cli/nativeBom.js +923 -15
- package/lib/core/activity.js +120 -2
- package/lib/core/env.js +44 -7
- package/lib/core/fs.js +174 -6
- package/lib/core/metadataProperties.js +97 -0
- package/lib/core/projectConfig.js +31 -4
- package/lib/core/userAgent.js +151 -0
- package/lib/ecosystems/bunutils.js +269 -101
- package/lib/ecosystems/cargoCache.js +364 -0
- package/lib/ecosystems/caxa.js +447 -7
- package/lib/ecosystems/cmakeResolver.js +66 -0
- package/lib/ecosystems/cppEvidence.js +104 -33
- package/lib/ecosystems/ecosystems.js +260 -99
- package/lib/ecosystems/golem.js +11 -1
- package/lib/ecosystems/gradleutils.js +185 -9
- package/lib/ecosystems/jsEvidence.js +19 -20
- package/lib/ecosystems/kosi.js +1263 -0
- package/lib/ecosystems/npmutils.js +110 -9
- package/lib/ecosystems/parsers-crystal.js +179 -0
- package/lib/ecosystems/parsers-dotnet.js +120 -49
- package/lib/ecosystems/parsers-elm.js +816 -0
- package/lib/ecosystems/parsers-gleam.js +1 -1
- package/lib/ecosystems/parsers-go.js +47 -9
- package/lib/ecosystems/parsers-js.js +171 -50
- package/lib/ecosystems/parsers-julia.js +268 -0
- package/lib/ecosystems/parsers-lua.js +218 -0
- package/lib/ecosystems/parsers-misc.js +919 -161
- 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 +27 -15
- package/lib/ecosystems/parsers-r.js +148 -0
- package/lib/ecosystems/parsers-rebar.js +411 -0
- package/lib/ecosystems/parsers-rust.js +954 -33
- 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/rubyutils.js +1426 -166
- package/lib/ecosystems/rusi.js +158 -7
- package/lib/evinser/evinser.js +547 -129
- package/lib/evinser/swiftsem.js +1914 -302
- package/lib/helpers/agenticToolutils.js +925 -0
- package/lib/helpers/bomSigner.js +652 -221
- 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/atomUtils.js +568 -31
- package/lib/inventory/auditCategories.js +8 -0
- package/lib/inventory/cbomutils.js +30 -0
- package/lib/inventory/cdxrs.js +110 -14
- package/lib/inventory/communityAiConfigParser.js +215 -2
- package/lib/inventory/depsUtils.js +183 -11
- package/lib/inventory/display.js +4 -5
- package/lib/inventory/dosai.js +627 -13
- package/lib/inventory/dynamic.js +39 -1
- package/lib/inventory/envcontext.js +9 -6
- package/lib/inventory/evidenceUtils.js +26 -5
- package/lib/inventory/fetchBatch.js +190 -19
- package/lib/inventory/fetchRate.js +74 -11
- package/lib/inventory/forgeEnricher.js +3 -2
- package/lib/inventory/jvmToolEnv.js +6 -5
- 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/plugins.js +3 -0
- package/lib/inventory/protobom.js +62 -89
- package/lib/inventory/protobomLoader.js +4 -0
- package/lib/inventory/purl.js +152 -3
- package/lib/inventory/rustFormulationParser.js +1 -1
- package/lib/inventory/sbomDocument.js +2 -70
- package/lib/inventory/source.js +47 -23
- package/lib/inventory/stylePackageRefs.js +41 -0
- package/lib/inventory/svelteUtils.js +524 -0
- package/lib/inventory/traceRunner.js +210 -21
- package/lib/managers/binary.js +115 -24
- package/lib/managers/docker.js +440 -20
- package/lib/managers/oci.js +39 -1
- package/lib/parsers/cmakeLists.js +452 -0
- package/lib/parsers/huggingfaceUtils.js +15 -7
- package/lib/parsers/largeJson.js +454 -0
- package/lib/parsers/npmrc.js +19 -1
- package/lib/parsers/onnx.js +294 -0
- package/lib/parsers/safetensors.js +114 -0
- package/lib/stages/postgen/introspection/markers.js +29 -6
- package/lib/stages/postgen/postgen.js +237 -16
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +462 -0
- package/lib/validator/bomValidator.js +6 -16
- package/lib/validator/index.js +48 -10
- package/lib/validator/reporters/console.js +3 -0
- package/lib/validator/reporters/json.js +1 -0
- package/lib/validator/reporters/sarif.js +7 -0
- package/package.json +27 -27
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +2 -1
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +33 -1
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +2 -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/env.d.ts +21 -0
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts +55 -0
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/metadataProperties.d.ts +39 -0
- package/types/lib/core/metadataProperties.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts +6 -2
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/userAgent.d.ts +56 -0
- package/types/lib/core/userAgent.d.ts.map +1 -0
- package/types/lib/ecosystems/bunutils.d.ts +12 -5
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
- 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 +14 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -1
- package/types/lib/ecosystems/cmakeResolver.d.ts +23 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/cppEvidence.d.ts +2 -2
- 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/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +40 -4
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts +5 -2
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts +86 -0
- package/types/lib/ecosystems/kosi.d.ts.map +1 -0
- package/types/lib/ecosystems/npmutils.d.ts +42 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
- 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-go.d.ts +10 -0
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +10 -4
- 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-lua.d.ts +50 -0
- package/types/lib/ecosystems/parsers-lua.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-misc.d.ts +90 -3
- 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/pythonutils.d.ts +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +143 -2
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts +13 -0
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +81 -2
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/swiftsem.d.ts +280 -15
- package/types/lib/evinser/swiftsem.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/bomSigner.d.ts +106 -13
- package/types/lib/helpers/bomSigner.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/atomUtils.d.ts +145 -3
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +4 -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/cdxrs.d.ts +8 -3
- package/types/lib/inventory/cdxrs.d.ts.map +1 -1
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/depsUtils.d.ts +15 -0
- package/types/lib/inventory/depsUtils.d.ts.map +1 -1
- package/types/lib/inventory/display.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +87 -1
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.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 +34 -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 +5 -4
- package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
- 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/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/purl.d.ts +71 -2
- package/types/lib/inventory/purl.d.ts.map +1 -1
- package/types/lib/inventory/sbomDocument.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/traceRunner.d.ts +47 -1
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +30 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +29 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +14 -0
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/parsers/cmakeLists.d.ts +76 -0
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts +8 -1
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
- package/types/lib/parsers/largeJson.d.ts +52 -0
- package/types/lib/parsers/largeJson.d.ts.map +1 -0
- package/types/lib/parsers/npmrc.d.ts +5 -0
- package/types/lib/parsers/npmrc.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/introspection/markers.d.ts +3 -2
- package/types/lib/stages/postgen/introspection/markers.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +33 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +10 -1
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/console.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -1
|
@@ -66,11 +66,12 @@ 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
|
-
encodeForPurl,
|
|
73
73
|
genericPurl,
|
|
74
|
+
nugetPurl,
|
|
74
75
|
pypiPurl,
|
|
75
76
|
} from "../inventory/purl.js";
|
|
76
77
|
import {
|
|
@@ -80,6 +81,10 @@ import {
|
|
|
80
81
|
} from "../inventory/spdx.js";
|
|
81
82
|
import { extractLicenseText, extractRepoUrl } from "../parsers/htmlExtract.js";
|
|
82
83
|
import { xml2js } from "../parsers/xml.js";
|
|
84
|
+
import {
|
|
85
|
+
localCargoMetadataEnabled,
|
|
86
|
+
readCargoCacheMetadata,
|
|
87
|
+
} from "./cargoCache.js";
|
|
83
88
|
import {
|
|
84
89
|
applyPypiClassifierMetadata,
|
|
85
90
|
applyPypiModuleNames,
|
|
@@ -814,11 +819,13 @@ export async function fetchPomXml({ urlPrefix, group, name, version }) {
|
|
|
814
819
|
// A direct POM may have been prefetched by getMvnMetadata's batch round.
|
|
815
820
|
// Parent POMs (fetched from inside fetchPomXmlAsJson) are not prefetched
|
|
816
821
|
// because their URL depends on the direct POM's content, so they fall
|
|
817
|
-
// through to the serial request
|
|
822
|
+
// through to the serial request. That fallback still reaches Maven Central
|
|
823
|
+
// and still counts against the same budget as the batch round, so it queues
|
|
824
|
+
// behind the same per-host gate rather than a second, ungoverned one.
|
|
818
825
|
try {
|
|
819
826
|
const res =
|
|
820
827
|
prefetchedResponse(prefetchedPoms, fullUrl) ||
|
|
821
|
-
(await cdxgenAgent.get(fullUrl));
|
|
828
|
+
(await withHostRateLimit(fullUrl, () => cdxgenAgent.get(fullUrl)));
|
|
822
829
|
return res.body;
|
|
823
830
|
} catch (_err) {
|
|
824
831
|
return undefined;
|
|
@@ -1792,24 +1799,61 @@ function getGoPkgFullName(group, name) {
|
|
|
1792
1799
|
/**
|
|
1793
1800
|
* Method to retrieve metadata for rust packages by querying crates
|
|
1794
1801
|
*
|
|
1802
|
+
* The local Cargo registry is consulted first, because crates.io's crawler
|
|
1803
|
+
* policy allows one request per second and a populated `~/.cargo` already
|
|
1804
|
+
* holds the license, description, repository, checksum and yanked flag for
|
|
1805
|
+
* every crate the build compiled.
|
|
1806
|
+
*
|
|
1807
|
+
* What it does not hold is publisher identity, so a caller that needs the
|
|
1808
|
+
* publisher-drift and release-cadence signals — the predictive audit does —
|
|
1809
|
+
* passes `preferLocalCache: false` and takes the slower registry path.
|
|
1810
|
+
*
|
|
1795
1811
|
* @param {Array} pkgList Package list
|
|
1812
|
+
* @param {Object} [options] Options
|
|
1813
|
+
* @param {boolean} [options.preferLocalCache=true] Answer from the local Cargo
|
|
1814
|
+
* registry where it can, and query crates.io only for the rest.
|
|
1796
1815
|
*/
|
|
1797
|
-
export async function getCratesMetadata(pkgList) {
|
|
1816
|
+
export async function getCratesMetadata(pkgList, options = {}) {
|
|
1798
1817
|
const CRATES_URL =
|
|
1799
1818
|
readEnvironmentVariable("RUST_CRATES_URL") ||
|
|
1800
1819
|
"https://crates.io/api/v1/crates/";
|
|
1801
1820
|
const cdepList = [];
|
|
1821
|
+
// The local Cargo registry answers first. crates.io allows one request per
|
|
1822
|
+
// second, so a populated ~/.cargo turns minutes of waiting into a few file
|
|
1823
|
+
// reads; only the crates it cannot account for reach the network.
|
|
1824
|
+
const servedLocally = new Set();
|
|
1825
|
+
const preferLocalCache = options.preferLocalCache !== false;
|
|
1826
|
+
if (preferLocalCache && localCargoMetadataEnabled()) {
|
|
1827
|
+
for (const p of pkgList) {
|
|
1828
|
+
if (!p?.name || !p?.version || p.version === "workspace") {
|
|
1829
|
+
continue;
|
|
1830
|
+
}
|
|
1831
|
+
if (applyCargoCacheMetadata(p)) {
|
|
1832
|
+
servedLocally.add(p);
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
if (DEBUG_MODE && servedLocally.size) {
|
|
1836
|
+
console.log(
|
|
1837
|
+
`Resolved ${servedLocally.size} of ${pkgList.length} crate(s) from the local Cargo registry.`,
|
|
1838
|
+
);
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
const needsRegistry = pkgList.filter(
|
|
1842
|
+
(p) =>
|
|
1843
|
+
p?.name &&
|
|
1844
|
+
p?.version &&
|
|
1845
|
+
p.version !== "workspace" &&
|
|
1846
|
+
!servedLocally.has(p),
|
|
1847
|
+
);
|
|
1802
1848
|
// Two URLs per crate — the crate document and its owners — fetched for the
|
|
1803
1849
|
// whole list at once. The `workspace` guard below is mirrored here so the
|
|
1804
1850
|
// batch does not request anything the loop would have skipped.
|
|
1805
1851
|
const prefetched = await prefetchJson(
|
|
1806
1852
|
prefetchEnabled()
|
|
1807
|
-
?
|
|
1808
|
-
|
|
1809
|
-
.
|
|
1810
|
-
|
|
1811
|
-
{ url: `${CRATES_URL + p.name}/owners` },
|
|
1812
|
-
])
|
|
1853
|
+
? needsRegistry.flatMap((p) => [
|
|
1854
|
+
{ url: CRATES_URL + p.name },
|
|
1855
|
+
{ url: `${CRATES_URL + p.name}/owners` },
|
|
1856
|
+
])
|
|
1813
1857
|
: [],
|
|
1814
1858
|
);
|
|
1815
1859
|
for (const p of pkgList) {
|
|
@@ -1818,23 +1862,35 @@ export async function getCratesMetadata(pkgList) {
|
|
|
1818
1862
|
cdepList.push(p);
|
|
1819
1863
|
continue;
|
|
1820
1864
|
}
|
|
1865
|
+
if (servedLocally.has(p)) {
|
|
1866
|
+
cdepList.push(p);
|
|
1867
|
+
continue;
|
|
1868
|
+
}
|
|
1821
1869
|
if (DEBUG_MODE) {
|
|
1822
1870
|
console.log(`Querying crates.io for ${p.name}@${p.version}`);
|
|
1823
1871
|
}
|
|
1824
1872
|
const crateUrl = CRATES_URL + p.name;
|
|
1873
|
+
// A prefetch miss falls back to a direct request, which must queue
|
|
1874
|
+
// behind the same crates.io gate the batch pool uses: the registry
|
|
1875
|
+
// allows one request per second and does not care which code path in
|
|
1876
|
+
// this process issued it.
|
|
1825
1877
|
const res =
|
|
1826
1878
|
prefetchedResponse(prefetched, crateUrl) ||
|
|
1827
|
-
(await
|
|
1828
|
-
|
|
1829
|
-
|
|
1879
|
+
(await withHostRateLimit(crateUrl, () =>
|
|
1880
|
+
cdxgenAgent.get(crateUrl, {
|
|
1881
|
+
responseType: "json",
|
|
1882
|
+
}),
|
|
1883
|
+
));
|
|
1830
1884
|
let ownersRes;
|
|
1831
1885
|
try {
|
|
1832
1886
|
const ownersUrl = `${crateUrl}/owners`;
|
|
1833
1887
|
ownersRes =
|
|
1834
1888
|
prefetchedResponse(prefetched, ownersUrl) ||
|
|
1835
|
-
(await
|
|
1836
|
-
|
|
1837
|
-
|
|
1889
|
+
(await withHostRateLimit(ownersUrl, () =>
|
|
1890
|
+
cdxgenAgent.get(ownersUrl, {
|
|
1891
|
+
responseType: "json",
|
|
1892
|
+
}),
|
|
1893
|
+
));
|
|
1838
1894
|
} catch (_err) {
|
|
1839
1895
|
ownersRes = undefined;
|
|
1840
1896
|
}
|
|
@@ -1904,6 +1960,86 @@ export async function getCratesMetadata(pkgList) {
|
|
|
1904
1960
|
return cdepList;
|
|
1905
1961
|
}
|
|
1906
1962
|
|
|
1963
|
+
/**
|
|
1964
|
+
* Apply the local Cargo registry's view of a crate to its component.
|
|
1965
|
+
*
|
|
1966
|
+
* Returns whether the component is complete enough to skip crates.io. The bar
|
|
1967
|
+
* is the license: `getCratesMetadata` runs only under `FETCH_LICENSE`, so a
|
|
1968
|
+
* crate whose license the local registry cannot name has not answered the
|
|
1969
|
+
* question that was asked and still needs the network. That happens when the
|
|
1970
|
+
* index knows a version but Cargo never extracted its sources — a crate the
|
|
1971
|
+
* lockfile pins but the build never compiled.
|
|
1972
|
+
*
|
|
1973
|
+
* Publisher identity has no local equivalent, so a component served from here
|
|
1974
|
+
* carries the publish time and yanked flag but none of the publisher-drift
|
|
1975
|
+
* properties; `cdx:cargo:metadataSource` records which it was.
|
|
1976
|
+
*
|
|
1977
|
+
* @param {Object} p Package component to enrich in place.
|
|
1978
|
+
* @returns {boolean} true when crates.io can be skipped for this crate.
|
|
1979
|
+
*/
|
|
1980
|
+
function applyCargoCacheMetadata(p) {
|
|
1981
|
+
const local = readCargoCacheMetadata(p.name, p.version);
|
|
1982
|
+
if (!local?.license) {
|
|
1983
|
+
return false;
|
|
1984
|
+
}
|
|
1985
|
+
p.license = local.license;
|
|
1986
|
+
if (local.description) {
|
|
1987
|
+
p.description = local.description;
|
|
1988
|
+
}
|
|
1989
|
+
if (local.repository) {
|
|
1990
|
+
p.repository = { url: local.repository };
|
|
1991
|
+
}
|
|
1992
|
+
if (local.homepage && local.homepage !== local.repository) {
|
|
1993
|
+
p.homepage = { url: local.homepage };
|
|
1994
|
+
}
|
|
1995
|
+
if (!p._integrity && local.checksum) {
|
|
1996
|
+
p._integrity = normalizeCargoIntegrity(local.checksum);
|
|
1997
|
+
}
|
|
1998
|
+
if (!p.properties) {
|
|
1999
|
+
p.properties = [];
|
|
2000
|
+
}
|
|
2001
|
+
p.properties.push({
|
|
2002
|
+
name: "cdx:cargo:metadataSource",
|
|
2003
|
+
value: "local-registry",
|
|
2004
|
+
});
|
|
2005
|
+
if (local.rustVersion) {
|
|
2006
|
+
p.properties.push({
|
|
2007
|
+
name: "cdx:cargo:rust_version",
|
|
2008
|
+
value: local.rustVersion,
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
if (local.latestVersion) {
|
|
2012
|
+
p.properties.push({
|
|
2013
|
+
name: "cdx:cargo:latest_version",
|
|
2014
|
+
value: local.latestVersion,
|
|
2015
|
+
});
|
|
2016
|
+
}
|
|
2017
|
+
if (typeof local.yanked === "boolean") {
|
|
2018
|
+
p.properties.push({
|
|
2019
|
+
name: "cdx:cargo:yanked",
|
|
2020
|
+
value: String(local.yanked),
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
if (local.publishTime) {
|
|
2024
|
+
p.properties.push({
|
|
2025
|
+
name: "cdx:cargo:publishTime",
|
|
2026
|
+
value: local.publishTime,
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
if (local.features && Object.keys(local.features).length) {
|
|
2030
|
+
p.properties.push({
|
|
2031
|
+
name: "cdx:cargo:features",
|
|
2032
|
+
value: JSON.stringify(local.features),
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
// The download path is a documented, stable URL shape rather than something
|
|
2036
|
+
// the API had to tell us, so it costs no request to state it.
|
|
2037
|
+
p.distribution = {
|
|
2038
|
+
url: `https://crates.io/api/v1/crates/${p.name}/${p.version}/download`,
|
|
2039
|
+
};
|
|
2040
|
+
return true;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
1907
2043
|
/**
|
|
1908
2044
|
* Method to retrieve metadata for dart packages by querying pub.dev
|
|
1909
2045
|
*
|
|
@@ -2168,17 +2304,23 @@ export async function extractJarArchive(jarFile, tempDir, jarNSMapping = {}) {
|
|
|
2168
2304
|
try {
|
|
2169
2305
|
const sha = await checksumFile("sha1", jf);
|
|
2170
2306
|
const searchurl = `https://central.sonatype.com/solrsearch/select?q=1:%22${sha}%22&rows=20&wt=json`;
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2307
|
+
// One Solr query per unidentified jar, against Central's origin
|
|
2308
|
+
// rather than its CDN. A directory of jars issues these back to
|
|
2309
|
+
// back, so they go through the same per-host gate the batch pool
|
|
2310
|
+
// uses (500 ms, serial) instead of a second, ungoverned path.
|
|
2311
|
+
const res = await withHostRateLimit(searchurl, () =>
|
|
2312
|
+
cdxgenAgent.get(searchurl, {
|
|
2313
|
+
responseType: "json",
|
|
2314
|
+
timeout: {
|
|
2315
|
+
lookup: 1000,
|
|
2316
|
+
connect: 5000,
|
|
2317
|
+
secureConnect: 5000,
|
|
2318
|
+
socket: 1000,
|
|
2319
|
+
send: 10000,
|
|
2320
|
+
response: 1000,
|
|
2321
|
+
},
|
|
2322
|
+
}),
|
|
2323
|
+
);
|
|
2182
2324
|
const data = res?.body ? res.body["response"] : undefined;
|
|
2183
2325
|
if (data && data["numFound"] === 1) {
|
|
2184
2326
|
const jarInfo = data["docs"][0];
|
|
@@ -2357,8 +2499,8 @@ export async function extractJarArchive(jarFile, tempDir, jarNSMapping = {}) {
|
|
|
2357
2499
|
}
|
|
2358
2500
|
}
|
|
2359
2501
|
const apkg = {
|
|
2360
|
-
group: group
|
|
2361
|
-
name: name
|
|
2502
|
+
group: group || "",
|
|
2503
|
+
name: name || "",
|
|
2362
2504
|
version,
|
|
2363
2505
|
purl,
|
|
2364
2506
|
evidence: {
|
|
@@ -2480,18 +2622,36 @@ async function unresolvedJarComponents(unresolvedJars, jarFile, tempDir) {
|
|
|
2480
2622
|
return components;
|
|
2481
2623
|
}
|
|
2482
2624
|
|
|
2625
|
+
/**
|
|
2626
|
+
* Property recording the NuGet release a versionless component's metadata was
|
|
2627
|
+
* read from, so the description and licence in the output can be traced.
|
|
2628
|
+
*/
|
|
2629
|
+
const METADATA_VERSION_PROP = "cdx:nuget:metadata_version";
|
|
2630
|
+
|
|
2483
2631
|
async function getNugetUrl() {
|
|
2484
2632
|
const req = "https://api.nuget.org/v3/index.json";
|
|
2485
|
-
const
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2633
|
+
const fallbackUrl = "https://api.nuget.org/v3/registration3/";
|
|
2634
|
+
let res;
|
|
2635
|
+
try {
|
|
2636
|
+
res = await cdxgenAgent.get(req, {
|
|
2637
|
+
responseType: "json",
|
|
2638
|
+
});
|
|
2639
|
+
} catch (err) {
|
|
2640
|
+
// Package lookups already degrade to unenriched components on error. An
|
|
2641
|
+
// unreachable service index used to reject here instead and abort the
|
|
2642
|
+
// whole BOM, so fall back to the well-known registration base.
|
|
2643
|
+
thoughtLog(
|
|
2644
|
+
`Unable to read the NuGet service index (${err.code || err.message}). Using ${fallbackUrl}.`,
|
|
2645
|
+
);
|
|
2646
|
+
return fallbackUrl;
|
|
2647
|
+
}
|
|
2648
|
+
const urls = res?.body?.resources || [];
|
|
2489
2649
|
for (const resource of urls) {
|
|
2490
2650
|
if (resource["@type"] === "RegistrationsBaseUrl/3.6.0") {
|
|
2491
2651
|
return resource["@id"];
|
|
2492
2652
|
}
|
|
2493
2653
|
}
|
|
2494
|
-
return
|
|
2654
|
+
return fallbackUrl;
|
|
2495
2655
|
}
|
|
2496
2656
|
|
|
2497
2657
|
/**
|
|
@@ -2555,60 +2715,46 @@ async function queryNuget(p, NUGET_URL) {
|
|
|
2555
2715
|
if (!items?.[0]) {
|
|
2556
2716
|
return [np, newBody, body];
|
|
2557
2717
|
}
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2718
|
+
// A component that states no version at all is not the same as one carrying a
|
|
2719
|
+
// `latest` or `0.0.0` placeholder. The placeholder asks to be replaced, so the
|
|
2720
|
+
// registry's newest release becomes the component's version. A missing version
|
|
2721
|
+
// means the manifest never said which release is in use - a `<Reference>` to an
|
|
2722
|
+
// assembly is the usual source - and the newest release is then only a key for
|
|
2723
|
+
// looking metadata up, never a version to write back. See #4359.
|
|
2724
|
+
const versionStated = p.version && !["0.0.0", "latest"].includes(p.version);
|
|
2725
|
+
let lookupVersion = p.version;
|
|
2726
|
+
if (!versionStated) {
|
|
2727
|
+
lookupVersion = setLatestVersion(items[items.length - 1].upper);
|
|
2728
|
+
np.version = p.version ? lookupVersion : undefined;
|
|
2729
|
+
np.metadataVersion = lookupVersion;
|
|
2730
|
+
}
|
|
2731
|
+
if (lookupVersion) {
|
|
2563
2732
|
for (const item of items) {
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
res = await cdxgenAgent.get(item["@id"], { responseType: "json" });
|
|
2575
|
-
for (const i of res.body.items.reverse()) {
|
|
2576
|
-
if (
|
|
2577
|
-
i.catalogEntry &&
|
|
2578
|
-
i.catalogEntry.version === coerceUp(np.version)
|
|
2579
|
-
) {
|
|
2580
|
-
newBody.push(i);
|
|
2581
|
-
return [np, newBody];
|
|
2582
|
-
}
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2733
|
+
const lower = compare(
|
|
2734
|
+
coerce(item.lower, { loose: true }),
|
|
2735
|
+
coerce(lookupVersion, { loose: true }),
|
|
2736
|
+
);
|
|
2737
|
+
const upper = compare(
|
|
2738
|
+
coerce(item.upper, { loose: true }),
|
|
2739
|
+
coerce(lookupVersion, { loose: true }),
|
|
2740
|
+
);
|
|
2741
|
+
if (lower === 1 || upper === -1) {
|
|
2742
|
+
continue;
|
|
2585
2743
|
}
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
for (const
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
)
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
coerce(np.version, { loose: true }),
|
|
2601
|
-
);
|
|
2602
|
-
if (lower !== 1 && upper !== -1) {
|
|
2603
|
-
for (const i of item.items.reverse()) {
|
|
2604
|
-
if (
|
|
2605
|
-
i.catalogEntry &&
|
|
2606
|
-
i.catalogEntry.version === coerceUp(np.version)
|
|
2607
|
-
) {
|
|
2608
|
-
newBody.push(i);
|
|
2609
|
-
return [np, newBody];
|
|
2610
|
-
}
|
|
2611
|
-
}
|
|
2744
|
+
// The registration index either inlines the leaves of each page or points
|
|
2745
|
+
// at a page that must be fetched.
|
|
2746
|
+
let leaves = item.items;
|
|
2747
|
+
if (!leaves) {
|
|
2748
|
+
res = await cdxgenAgent.get(item["@id"], { responseType: "json" });
|
|
2749
|
+
leaves = res.body.items;
|
|
2750
|
+
}
|
|
2751
|
+
for (const i of leaves.reverse()) {
|
|
2752
|
+
if (
|
|
2753
|
+
i.catalogEntry &&
|
|
2754
|
+
i.catalogEntry.version === coerceUp(lookupVersion)
|
|
2755
|
+
) {
|
|
2756
|
+
newBody.push(i);
|
|
2757
|
+
return [np, newBody];
|
|
2612
2758
|
}
|
|
2613
2759
|
}
|
|
2614
2760
|
}
|
|
@@ -2673,25 +2819,36 @@ export async function getNugetMetadata(pkgList, dependencies = undefined) {
|
|
|
2673
2819
|
[np, newBody] = await queryNuget(p, NUGET_URL);
|
|
2674
2820
|
if (p.version !== np.version) {
|
|
2675
2821
|
const oldRef = p["bom-ref"];
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
namespace: "" || null,
|
|
2680
|
-
name: np.name,
|
|
2681
|
-
version: np.version || null,
|
|
2682
|
-
}),
|
|
2683
|
-
);
|
|
2684
|
-
depRepList[oldRef] = p["bom-ref"];
|
|
2822
|
+
// The purl is rebuilt alongside the bom-ref. Leaving it behind let a
|
|
2823
|
+
// component state one version in `version` and another - or none - in
|
|
2824
|
+
// its purl, which is what a scanner range matches on. See #4359.
|
|
2685
2825
|
p.version = np.version;
|
|
2826
|
+
applyPurl(p, nugetPurl(np.name, np.version));
|
|
2827
|
+
if (oldRef && p["bom-ref"] !== oldRef) {
|
|
2828
|
+
depRepList[oldRef] = p["bom-ref"];
|
|
2829
|
+
}
|
|
2686
2830
|
}
|
|
2687
2831
|
if (newBody && newBody.length > 0) {
|
|
2688
2832
|
body = newBody[0];
|
|
2689
2833
|
}
|
|
2690
2834
|
if (body) {
|
|
2691
2835
|
metadata_cache[cacheKey] = body;
|
|
2692
|
-
//
|
|
2693
|
-
|
|
2694
|
-
|
|
2836
|
+
// The component states no version, so the description and licence
|
|
2837
|
+
// below were read from whichever release the lookup fell back to.
|
|
2838
|
+
// That release is recorded rather than adopted as the version: a
|
|
2839
|
+
// version cdxgen chose is not a version the project declared.
|
|
2840
|
+
if (!p.version && np.metadataVersion) {
|
|
2841
|
+
p.properties = p.properties || [];
|
|
2842
|
+
if (
|
|
2843
|
+
!p.properties.some(
|
|
2844
|
+
(prop) => prop.name === METADATA_VERSION_PROP,
|
|
2845
|
+
)
|
|
2846
|
+
) {
|
|
2847
|
+
p.properties.push({
|
|
2848
|
+
name: METADATA_VERSION_PROP,
|
|
2849
|
+
value: np.metadataVersion,
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2695
2852
|
}
|
|
2696
2853
|
p.description = body.catalogEntry.description;
|
|
2697
2854
|
if (body.catalogEntry.authors) {
|
|
@@ -2720,8 +2877,12 @@ export async function getNugetMetadata(pkgList, dependencies = undefined) {
|
|
|
2720
2877
|
}
|
|
2721
2878
|
if (body.catalogEntry.projectUrl) {
|
|
2722
2879
|
p.repository = { url: body.catalogEntry.projectUrl };
|
|
2880
|
+
// A versionless component gets the package's landing page. Pasting
|
|
2881
|
+
// an undefined version into the path produced a 404 link.
|
|
2723
2882
|
p.homepage = {
|
|
2724
|
-
url:
|
|
2883
|
+
url: p.version
|
|
2884
|
+
? `https://www.nuget.org/packages/${p.name}/${p.version}/`
|
|
2885
|
+
: `https://www.nuget.org/packages/${p.name}/`,
|
|
2725
2886
|
};
|
|
2726
2887
|
if (
|
|
2727
2888
|
(!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 =
|