@cdxgen/cdxgen 13.3.0 → 13.4.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 +9 -6
- package/bin/cdxgen.js +90 -26
- package/bin/evinse.js +18 -1
- package/bin/repl.js +86 -0
- package/bin/sign.js +45 -15
- package/bin/tracebom.js +5 -1
- package/bin/validate.js +84 -18
- package/bin/verify.js +155 -86
- package/data/helpers/init.gradle +46 -21
- package/data/remediations.json +61 -0
- package/data/rules/dependency-sources.yaml +67 -0
- package/data/rules/scala-evidence.yaml +115 -0
- package/lib/audit/index.js +38 -6
- package/lib/cli/index.js +113 -54
- package/lib/cli/jsBom.js +50 -29
- package/lib/cli/jvmBom.js +665 -138
- package/lib/cli/managedBom.js +320 -200
- package/lib/cli/nativeBom.js +139 -30
- package/lib/core/activity.js +12 -0
- package/lib/core/env.js +17 -9
- package/lib/core/fs.js +3 -2
- package/lib/core/httpClient.js +159 -24
- package/lib/core/pluginRun.js +184 -0
- package/lib/core/processTree.js +100 -0
- package/lib/core/runState.js +39 -0
- package/lib/core/toml.js +72 -0
- package/lib/ecosystems/asarutils.js +4 -2
- package/lib/ecosystems/bunutils.js +5 -7
- package/lib/ecosystems/cargoCache.js +231 -8
- package/lib/ecosystems/cmakeResolver.js +10 -21
- package/lib/ecosystems/cppBuildContext.js +631 -0
- package/lib/ecosystems/cppEvidence.js +337 -22
- package/lib/ecosystems/cppIncludeResolver.js +294 -0
- package/lib/ecosystems/denoutils.js +93 -66
- package/lib/ecosystems/ecosystems.js +1967 -788
- package/lib/ecosystems/golem.js +28 -12
- package/lib/ecosystems/gradleutils.js +314 -30
- package/lib/ecosystems/jsEvidence.js +85 -24
- package/lib/ecosystems/kosi.js +21 -4
- package/lib/ecosystems/npmutils.js +64 -0
- package/lib/ecosystems/parsers-dotnet.js +567 -151
- package/lib/ecosystems/parsers-elm.js +46 -28
- package/lib/ecosystems/parsers-gleam.js +3 -4
- package/lib/ecosystems/parsers-go.js +324 -61
- package/lib/ecosystems/parsers-js.js +92 -26
- package/lib/ecosystems/parsers-julia.js +2 -3
- package/lib/ecosystems/parsers-jvm.js +204 -12
- package/lib/ecosystems/parsers-misc.js +182 -55
- package/lib/ecosystems/parsers-python.js +141 -10
- package/lib/ecosystems/parsers-rust.js +4 -4
- package/lib/ecosystems/parsers-terraform.js +1573 -19
- package/lib/ecosystems/pythonutils.js +102 -6
- package/lib/ecosystems/remote/huggingface.js +3 -0
- package/lib/ecosystems/rubyutils.js +67 -17
- package/lib/ecosystems/rusi.js +22 -9
- package/lib/ecosystems/sbtutils.js +243 -187
- package/lib/ecosystems/scalacliutils.js +342 -0
- package/lib/ecosystems/scalasem.js +2618 -0
- package/lib/ecosystems/terraformRegistry.js +288 -0
- package/lib/ecosystems/utils.js +2 -0
- package/lib/ecosystems/vendoredCode.js +156 -0
- package/lib/evinser/evinser.js +578 -69
- package/lib/helpers/agenticToolutils.js +2 -2
- package/lib/helpers/bomSigner.js +576 -128
- package/lib/inventory/aiCollector.js +4 -1
- package/lib/inventory/analyzer.js +110 -127
- package/lib/inventory/atomUtils.js +171 -48
- package/lib/inventory/auditCategories.js +7 -0
- package/lib/inventory/buildToolRateLimit.js +144 -0
- package/lib/inventory/cacheCommands.js +2 -1
- package/lib/inventory/cmakeBuildDirs.js +254 -0
- package/lib/inventory/deps.js +501 -124
- package/lib/inventory/dosai.js +248 -44
- package/lib/inventory/dosaiParsers.js +310 -15
- package/lib/inventory/dynamic.js +52 -6
- package/lib/inventory/evidenceUtils.js +154 -109
- package/lib/inventory/fetchBatch.js +574 -38
- package/lib/inventory/fetchDiskCache.js +597 -0
- package/lib/inventory/forgeEnricher.js +14 -5
- package/lib/inventory/jvmLocalRepos.js +917 -0
- package/lib/inventory/mcpConfigParser.js +2 -3
- package/lib/inventory/parentSelection.js +146 -0
- package/lib/inventory/rustFormulationParser.js +3 -4
- package/lib/inventory/scalaCoords.js +153 -0
- package/lib/inventory/source.js +8 -8
- package/lib/inventory/spdx.js +101 -0
- package/lib/inventory/traceRunner.js +88 -7
- package/lib/inventory/tracedCrypto.js +294 -0
- package/lib/managers/docker.js +33 -32
- package/lib/managers/oci.js +24 -2
- package/lib/parsers/cmakeCache.js +69 -0
- package/lib/parsers/cmakeLists.js +16 -2
- package/lib/parsers/cmakePresets.js +400 -0
- package/lib/parsers/compileCommands.js +557 -0
- package/lib/parsers/strictJson.js +322 -0
- package/lib/parsers/terraformConfig.js +1073 -0
- package/lib/parsers/terraformSource.js +652 -0
- package/lib/server/server.js +23 -0
- package/lib/stages/postgen/introspection/markers.js +1 -1
- package/lib/stages/postgen/postgen.js +15 -1
- package/lib/stages/postgen/specVersionCompat.js +32 -0
- package/lib/validator/index.js +25 -10
- package/lib/validator/reporters/json.js +1 -0
- package/package.json +21 -21
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +24 -1
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts +7 -4
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts +3 -1
- 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 +9 -0
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/httpClient.d.ts +13 -8
- package/types/lib/core/httpClient.d.ts.map +1 -1
- package/types/lib/core/pluginRun.d.ts +97 -0
- package/types/lib/core/pluginRun.d.ts.map +1 -0
- package/types/lib/core/processTree.d.ts +36 -0
- package/types/lib/core/processTree.d.ts.map +1 -0
- package/types/lib/core/runState.d.ts +29 -0
- package/types/lib/core/runState.d.ts.map +1 -0
- package/types/lib/core/toml.d.ts +20 -0
- package/types/lib/core/toml.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
- package/types/lib/ecosystems/cargoCache.d.ts +12 -0
- package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
- package/types/lib/ecosystems/cmakeResolver.d.ts +5 -3
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
- package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +18 -2
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
- package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +9 -3
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts +62 -13
- 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 +50 -0
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts.map +1 -1
- package/types/lib/ecosystems/npmutils.d.ts +15 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-dotnet.d.ts +118 -4
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-go.d.ts +44 -2
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +6 -1
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts +46 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +3 -1
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +53 -3
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
- package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +27 -2
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +21 -1
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/ecosystems/sbtutils.d.ts +88 -2
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
- package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
- package/types/lib/ecosystems/scalasem.d.ts +311 -0
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +2 -2
- package/types/lib/ecosystems/utils.d.ts.map +1 -1
- package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
- package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +75 -8
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +80 -4
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/analyzer.d.ts.map +1 -1
- package/types/lib/inventory/atomUtils.d.ts +82 -10
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +3 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
- package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +2 -1
- package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
- package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
- package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +59 -1
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +57 -8
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dosaiParsers.d.ts +53 -7
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts +10 -0
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts +19 -4
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/fetchBatch.d.ts +83 -14
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
- package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/parentSelection.d.ts +34 -0
- package/types/lib/inventory/parentSelection.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/scalaCoords.d.ts +80 -0
- package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/spdx.d.ts +9 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -1
- package/types/lib/inventory/traceRunner.d.ts +12 -0
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/inventory/tracedCrypto.d.ts +42 -0
- package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +3 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/parsers/cmakeCache.d.ts +16 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
- package/types/lib/parsers/cmakeLists.d.ts +2 -1
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -1
- package/types/lib/parsers/cmakePresets.d.ts +78 -0
- package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
- package/types/lib/parsers/compileCommands.d.ts +115 -0
- package/types/lib/parsers/compileCommands.d.ts.map +1 -0
- package/types/lib/parsers/strictJson.d.ts +46 -0
- package/types/lib/parsers/strictJson.d.ts.map +1 -0
- package/types/lib/parsers/terraformConfig.d.ts +70 -0
- package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
- package/types/lib/parsers/terraformSource.d.ts +66 -0
- package/types/lib/parsers/terraformSource.d.ts.map +1 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +8 -0
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
3
|
+
import { join, posix, resolve } from "node:path";
|
|
4
|
+
import { gunzipSync } from "node:zlib";
|
|
4
5
|
|
|
5
|
-
import
|
|
6
|
+
import { Parser as TarParser } from "tar";
|
|
6
7
|
|
|
7
8
|
import { readEnvironmentVariable } from "../core/activity.js";
|
|
8
9
|
import { safeExistsSync } from "../core/fs.js";
|
|
10
|
+
import { registerRunReset } from "../core/runState.js";
|
|
11
|
+
import { parseToml } from "../core/toml.js";
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Crate metadata read from the local Cargo registry, without any network.
|
|
@@ -69,6 +72,8 @@ export function resetCargoCacheState() {
|
|
|
69
72
|
_registryDirs = undefined;
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
registerRunReset("cargo:local-registry", resetCargoCacheState);
|
|
76
|
+
|
|
72
77
|
/**
|
|
73
78
|
* Whether the local registry should be consulted before crates.io.
|
|
74
79
|
*
|
|
@@ -101,15 +106,16 @@ export function getCargoRegistryDir() {
|
|
|
101
106
|
* private registry has more than one, and the crate being looked up may live
|
|
102
107
|
* in any of them, so all are searched.
|
|
103
108
|
*
|
|
104
|
-
* @returns {{src: string[], index: string[]}} Absolute
|
|
109
|
+
* @returns {{src: string[], index: string[], cache: string[]}} Absolute
|
|
110
|
+
* directory paths.
|
|
105
111
|
*/
|
|
106
112
|
function registryDirs() {
|
|
107
113
|
if (_registryDirs) {
|
|
108
114
|
return _registryDirs;
|
|
109
115
|
}
|
|
110
116
|
const root = getCargoRegistryDir();
|
|
111
|
-
_registryDirs = { src: [], index: [] };
|
|
112
|
-
for (const kind of ["src", "index"]) {
|
|
117
|
+
_registryDirs = { src: [], index: [], cache: [] };
|
|
118
|
+
for (const kind of ["src", "index", "cache"]) {
|
|
113
119
|
const base = join(root, kind);
|
|
114
120
|
try {
|
|
115
121
|
for (const entry of readdirSync(base, { withFileTypes: true })) {
|
|
@@ -133,7 +139,7 @@ function registryDirs() {
|
|
|
133
139
|
* @returns {CargoCacheMetadata|undefined} Metadata, or undefined when neither
|
|
134
140
|
* local source has this crate.
|
|
135
141
|
*/
|
|
136
|
-
export function readCargoCacheMetadata(name, version) {
|
|
142
|
+
export async function readCargoCacheMetadata(name, version) {
|
|
137
143
|
if (!name || !version) {
|
|
138
144
|
return undefined;
|
|
139
145
|
}
|
|
@@ -144,6 +150,15 @@ export function readCargoCacheMetadata(name, version) {
|
|
|
144
150
|
Object.assign(result, manifest.values);
|
|
145
151
|
sources.push(manifest.source);
|
|
146
152
|
}
|
|
153
|
+
const archive = await readCachedCrateArchive(name, version);
|
|
154
|
+
if (archive) {
|
|
155
|
+
for (const [key, value] of Object.entries(archive.values)) {
|
|
156
|
+
if (result[key] === undefined) {
|
|
157
|
+
result[key] = value;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
sources.push(archive.source);
|
|
161
|
+
}
|
|
147
162
|
const index = readIndexEntry(name, version);
|
|
148
163
|
if (index) {
|
|
149
164
|
// The manifest is authoritative for the fields both carry, since it is the
|
|
@@ -158,6 +173,198 @@ export function readCargoCacheMetadata(name, version) {
|
|
|
158
173
|
return sources.length ? result : undefined;
|
|
159
174
|
}
|
|
160
175
|
|
|
176
|
+
/**
|
|
177
|
+
* A `.crate` archive larger than this is not opened for its manifest. Crates
|
|
178
|
+
* this size are rare, and the archive may be untrusted input.
|
|
179
|
+
*/
|
|
180
|
+
const CRATE_ARCHIVE_MAX_BYTES = 16 * 1024 * 1024;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* An archive that unpacks to more than this is not read, so a small archive
|
|
184
|
+
* that expands without bound costs bounded time and memory.
|
|
185
|
+
*/
|
|
186
|
+
const CRATE_UNPACKED_MAX_BYTES = 64 * 1024 * 1024;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* A single entry larger than this is not read out of a `.crate` archive.
|
|
190
|
+
*/
|
|
191
|
+
const CRATE_ENTRY_MAX_BYTES = 1024 * 1024;
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* The `license-file` of a manifest as a path inside the crate, or undefined
|
|
195
|
+
* when it points anywhere else. The manifest is the crate author's, so a path
|
|
196
|
+
* that climbs out of the crate must never be followed.
|
|
197
|
+
*
|
|
198
|
+
* @param {*} licenseFile The manifest's `license-file` value
|
|
199
|
+
* @returns {string|undefined} Normalised relative path
|
|
200
|
+
*/
|
|
201
|
+
function crateLicenseFilePath(licenseFile) {
|
|
202
|
+
if (typeof licenseFile !== "string" || !licenseFile.trim()) {
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
const normalized = posix.normalize(licenseFile.trim().replaceAll("\\", "/"));
|
|
206
|
+
if (
|
|
207
|
+
normalized.startsWith("/") ||
|
|
208
|
+
normalized === ".." ||
|
|
209
|
+
normalized.startsWith("../") ||
|
|
210
|
+
/^[A-Za-z]:/.test(normalized)
|
|
211
|
+
) {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
return normalized;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The unpacked tar data of a `.crate` archive, within the size bounds.
|
|
219
|
+
*
|
|
220
|
+
* @param {string} crateFile Path to the `.crate` archive (a gzipped tar)
|
|
221
|
+
* @returns {Buffer|undefined}
|
|
222
|
+
*/
|
|
223
|
+
function unpackCrateArchive(crateFile) {
|
|
224
|
+
try {
|
|
225
|
+
if (statSync(crateFile).size > CRATE_ARCHIVE_MAX_BYTES) {
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
return gunzipSync(readFileSync(crateFile), {
|
|
229
|
+
maxOutputLength: CRATE_UNPACKED_MAX_BYTES,
|
|
230
|
+
});
|
|
231
|
+
} catch {
|
|
232
|
+
// An unreadable archive, or one that unpacks past the bound, is the same
|
|
233
|
+
// as none: the network path answers.
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Read one file out of unpacked `.crate` tar data.
|
|
240
|
+
*
|
|
241
|
+
* @param {Buffer} tarData Unpacked tar data
|
|
242
|
+
* @param {string} entryName Entry path relative to the archive root
|
|
243
|
+
* @returns {Promise<string|undefined>} The entry's text, or undefined
|
|
244
|
+
*/
|
|
245
|
+
function readCrateArchiveEntry(tarData, entryName) {
|
|
246
|
+
return new Promise((resolvePromise) => {
|
|
247
|
+
let content;
|
|
248
|
+
const parser = new TarParser({
|
|
249
|
+
onReadEntry: (entry) => {
|
|
250
|
+
const path = entry.path.startsWith("./")
|
|
251
|
+
? entry.path.slice(2)
|
|
252
|
+
: entry.path;
|
|
253
|
+
if (
|
|
254
|
+
content !== undefined ||
|
|
255
|
+
path !== entryName ||
|
|
256
|
+
entry.size > CRATE_ENTRY_MAX_BYTES
|
|
257
|
+
) {
|
|
258
|
+
entry.resume();
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const chunks = [];
|
|
262
|
+
entry.on("data", (chunk) => chunks.push(chunk));
|
|
263
|
+
entry.on("end", () => {
|
|
264
|
+
content = Buffer.concat(chunks).toString("utf-8");
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
parser.on("error", () => resolvePromise(undefined));
|
|
269
|
+
parser.on("close", () => resolvePromise(content));
|
|
270
|
+
parser.end(tarData);
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* The manifest values of a `.crate` archive, read without extracting it.
|
|
276
|
+
*
|
|
277
|
+
* @param {string} crateFile Path to the `.crate` archive
|
|
278
|
+
* @param {string} name Crate name, for the archive's inner directory
|
|
279
|
+
* @param {string} version Crate version
|
|
280
|
+
* @returns {Promise<{values: Object, source: string}|undefined>}
|
|
281
|
+
*/
|
|
282
|
+
export async function readCrateArchiveValues(crateFile, name, version) {
|
|
283
|
+
if (!name || !version) {
|
|
284
|
+
return undefined;
|
|
285
|
+
}
|
|
286
|
+
const tarData = unpackCrateArchive(crateFile);
|
|
287
|
+
if (!tarData) {
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
const prefix = `${name}-${version}`;
|
|
291
|
+
const manifestData = await readCrateArchiveEntry(
|
|
292
|
+
tarData,
|
|
293
|
+
`${prefix}/Cargo.toml`,
|
|
294
|
+
);
|
|
295
|
+
if (!manifestData) {
|
|
296
|
+
return undefined;
|
|
297
|
+
}
|
|
298
|
+
let parsed;
|
|
299
|
+
try {
|
|
300
|
+
parsed = parseToml(manifestData);
|
|
301
|
+
} catch {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
const pkg = parsed?.package;
|
|
305
|
+
if (!pkg || typeof pkg !== "object") {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
const values = {};
|
|
309
|
+
assignString(values, "description", pkg.description);
|
|
310
|
+
assignString(values, "repository", pkg.repository);
|
|
311
|
+
assignString(values, "homepage", pkg.homepage);
|
|
312
|
+
assignString(values, "rustVersion", pkg["rust-version"]);
|
|
313
|
+
assignString(values, "license", pkg.license);
|
|
314
|
+
const licenseFile = crateLicenseFilePath(pkg["license-file"]);
|
|
315
|
+
if (licenseFile && !values.license) {
|
|
316
|
+
assignLicenseText(
|
|
317
|
+
values,
|
|
318
|
+
await readCrateArchiveEntry(tarData, `${prefix}/${licenseFile}`),
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
return { values, source: crateFile };
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* The `.crate` archive of a crate version held in the registry cache, which is
|
|
326
|
+
* the only local copy of a crate the build downloaded but never compiled.
|
|
327
|
+
*
|
|
328
|
+
* @param {string} name Crate name.
|
|
329
|
+
* @param {string} version Exact version.
|
|
330
|
+
* @returns {Promise<{values: Object, source: string}|undefined>}
|
|
331
|
+
*/
|
|
332
|
+
async function readCachedCrateArchive(name, version) {
|
|
333
|
+
for (const dir of registryDirs().cache) {
|
|
334
|
+
const crateFile = join(dir, `${name}-${version}.crate`);
|
|
335
|
+
if (!safeExistsSync(crateFile)) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
const archive = await readCrateArchiveValues(crateFile, name, version);
|
|
339
|
+
if (archive) {
|
|
340
|
+
return archive;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Record a `license-file` notice as a component licence, following the shape
|
|
348
|
+
* cdxgen records licence file text in elsewhere: a CUSTOM licence name with
|
|
349
|
+
* the notice as its text.
|
|
350
|
+
*
|
|
351
|
+
* @param {Object} values Manifest values so far, updated in place
|
|
352
|
+
* @param {string|undefined} text The notice text
|
|
353
|
+
*/
|
|
354
|
+
function assignLicenseText(values, text) {
|
|
355
|
+
if (!text?.length) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
values.licenses = [
|
|
359
|
+
{
|
|
360
|
+
license: {
|
|
361
|
+
name: "CUSTOM",
|
|
362
|
+
text: { contentType: "text/plain", content: text },
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
];
|
|
366
|
+
}
|
|
367
|
+
|
|
161
368
|
/**
|
|
162
369
|
* Read the normalised `Cargo.toml` of an extracted crate.
|
|
163
370
|
*
|
|
@@ -173,7 +380,7 @@ function readExtractedManifest(name, version) {
|
|
|
173
380
|
}
|
|
174
381
|
let parsed;
|
|
175
382
|
try {
|
|
176
|
-
parsed =
|
|
383
|
+
parsed = parseToml(readFileSync(manifestFile, "utf-8"));
|
|
177
384
|
} catch {
|
|
178
385
|
// A manifest that does not parse is not worth a warning: the network
|
|
179
386
|
// path still has the answer.
|
|
@@ -189,8 +396,24 @@ function readExtractedManifest(name, version) {
|
|
|
189
396
|
assignString(values, "homepage", pkg.homepage);
|
|
190
397
|
assignString(values, "rustVersion", pkg["rust-version"]);
|
|
191
398
|
// A crate may carry `license` or, for a non-SPDX license, `license-file`.
|
|
192
|
-
//
|
|
399
|
+
// The expression is used as the licence; a licence file is recorded as a
|
|
400
|
+
// CUSTOM licence carrying the notice text, the way cdxgen records licence
|
|
401
|
+
// file text elsewhere.
|
|
193
402
|
assignString(values, "license", pkg.license);
|
|
403
|
+
const licenseFile = crateLicenseFilePath(pkg["license-file"]);
|
|
404
|
+
if (licenseFile && !values.license) {
|
|
405
|
+
try {
|
|
406
|
+
assignLicenseText(
|
|
407
|
+
values,
|
|
408
|
+
readFileSync(join(dir, `${name}-${version}`, licenseFile), {
|
|
409
|
+
encoding: "utf-8",
|
|
410
|
+
}),
|
|
411
|
+
);
|
|
412
|
+
} catch {
|
|
413
|
+
// A licence file that cannot be read leaves the licence to the network
|
|
414
|
+
// path, exactly as an absent one does.
|
|
415
|
+
}
|
|
416
|
+
}
|
|
194
417
|
if (parsed.features && typeof parsed.features === "object") {
|
|
195
418
|
values.features = parsed.features;
|
|
196
419
|
}
|
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
isSecureMode,
|
|
18
18
|
recordSensitiveFileRead,
|
|
19
19
|
} from "../core/activity.js";
|
|
20
|
-
import {
|
|
20
|
+
import { safeExistsSync } from "../core/fs.js";
|
|
21
|
+
import { cmakeBuildDirCandidates } from "../inventory/cmakeBuildDirs.js";
|
|
21
22
|
import {
|
|
22
23
|
execGitCommand,
|
|
23
24
|
GIT_COMMAND,
|
|
@@ -35,9 +36,6 @@ import {
|
|
|
35
36
|
submodulePurlCoordinates,
|
|
36
37
|
} from "../parsers/gitmodules.js";
|
|
37
38
|
|
|
38
|
-
const FETCHCONTENT_CANDIDATE_GLOBS = ["build", "out"];
|
|
39
|
-
const CMAKE_BUILD_DIR_GLOBS = ["cmake-build-*"];
|
|
40
|
-
|
|
41
39
|
/**
|
|
42
40
|
* Make an absolute build-machine path repo-relative. Returns `null` when the
|
|
43
41
|
* path does not lie under the scan root (so the caller can drop it rather than
|
|
@@ -61,9 +59,11 @@ function toRepoRelative(absPath, scanRoot) {
|
|
|
61
59
|
/**
|
|
62
60
|
* Detect the build directory that holds a `CMakeCache.txt`.
|
|
63
61
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
62
|
+
* An explicit `--cmake-cache <path>` option (passed via `options.cmakeCache`)
|
|
63
|
+
* takes precedence and skips autodetection. Otherwise the project's build
|
|
64
|
+
* directories are searched in order: those its CMake presets configure, then
|
|
65
|
+
* the conventional `build`, `out`, `builddir` and `cmake-build-` directories
|
|
66
|
+
* (see `cmakeBuildDirCandidates`).
|
|
67
67
|
*
|
|
68
68
|
* @param {string} path Project scan root
|
|
69
69
|
* @param {Object} options CLI options; `options.cmakeCache` is an explicit override
|
|
@@ -80,26 +80,15 @@ export function detectCmakeBuildDir(path, options) {
|
|
|
80
80
|
}
|
|
81
81
|
return null;
|
|
82
82
|
}
|
|
83
|
-
for (const
|
|
84
|
-
const cacheFile = join(
|
|
83
|
+
for (const buildDir of cmakeBuildDirCandidates(path, options)) {
|
|
84
|
+
const cacheFile = join(buildDir, "CMakeCache.txt");
|
|
85
85
|
if (safeExistsSync(cacheFile)) {
|
|
86
86
|
recordSensitiveFileRead(cacheFile, {
|
|
87
87
|
label: "CMakeCache.txt (autodetected)",
|
|
88
88
|
});
|
|
89
|
-
return { cacheFile, buildDir
|
|
89
|
+
return { cacheFile, buildDir };
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
const buildDirs = getAllFiles(path, `{${CMAKE_BUILD_DIR_GLOBS.join(",")}}`, {
|
|
93
|
-
noIgnore: true,
|
|
94
|
-
}).filter((f) => safeExistsSync(join(f, "CMakeCache.txt")));
|
|
95
|
-
if (buildDirs.length) {
|
|
96
|
-
const buildDir = buildDirs[0];
|
|
97
|
-
const cacheFile = join(buildDir, "CMakeCache.txt");
|
|
98
|
-
recordSensitiveFileRead(cacheFile, {
|
|
99
|
-
label: "CMakeCache.txt (autodetected)",
|
|
100
|
-
});
|
|
101
|
-
return { cacheFile, buildDir };
|
|
102
|
-
}
|
|
103
92
|
return null;
|
|
104
93
|
}
|
|
105
94
|
|