@cdxgen/cdxgen 13.2.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 +33 -14
- package/bin/cdxgen.js +310 -138
- package/bin/evinse.js +22 -0
- package/bin/repl.js +86 -0
- package/bin/sign.js +119 -15
- package/bin/tracebom.js +69 -5
- package/bin/validate.js +107 -19
- package/bin/verify.js +172 -63
- package/data/helpers/init.gradle +46 -21
- package/data/remediations.json +85 -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/bomAssembly.js +105 -15
- package/lib/cli/cliOptions.js +93 -1
- package/lib/cli/index.js +156 -58
- package/lib/cli/jsBom.js +99 -53
- package/lib/cli/jvmBom.js +708 -147
- package/lib/cli/managedBom.js +415 -224
- package/lib/cli/nativeBom.js +264 -44
- package/lib/core/activity.js +12 -0
- package/lib/core/env.js +22 -15
- package/lib/core/fs.js +176 -7
- package/lib/core/httpClient.js +159 -24
- package/lib/core/metadataProperties.js +97 -0
- package/lib/core/pluginRun.js +184 -0
- package/lib/core/processTree.js +100 -0
- package/lib/core/projectConfig.js +31 -4
- 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 +274 -108
- package/lib/ecosystems/cargoCache.js +231 -8
- package/lib/ecosystems/caxa.js +434 -2
- package/lib/ecosystems/cmakeResolver.js +76 -21
- package/lib/ecosystems/cppBuildContext.js +631 -0
- package/lib/ecosystems/cppEvidence.js +399 -51
- package/lib/ecosystems/cppIncludeResolver.js +294 -0
- package/lib/ecosystems/denoutils.js +93 -66
- package/lib/ecosystems/ecosystems.js +1983 -793
- package/lib/ecosystems/golem.js +28 -12
- package/lib/ecosystems/gradleutils.js +356 -37
- package/lib/ecosystems/jsEvidence.js +104 -44
- package/lib/ecosystems/kosi.js +31 -7
- package/lib/ecosystems/npmutils.js +174 -9
- package/lib/ecosystems/parsers-dotnet.js +616 -159
- package/lib/ecosystems/parsers-elm.js +46 -28
- package/lib/ecosystems/parsers-gleam.js +3 -4
- package/lib/ecosystems/parsers-go.js +371 -70
- package/lib/ecosystems/parsers-js.js +263 -76
- package/lib/ecosystems/parsers-julia.js +2 -3
- package/lib/ecosystems/parsers-jvm.js +204 -12
- package/lib/ecosystems/parsers-misc.js +929 -216
- package/lib/ecosystems/parsers-python.js +167 -24
- package/lib/ecosystems/parsers-rust.js +28 -22
- 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 +1492 -182
- package/lib/ecosystems/rusi.js +54 -10
- 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 +1008 -191
- package/lib/evinser/swiftsem.js +1914 -302
- package/lib/helpers/agenticToolutils.js +2 -2
- package/lib/helpers/bomSigner.js +1101 -222
- package/lib/inventory/aiCollector.js +4 -1
- package/lib/inventory/analyzer.js +110 -127
- package/lib/inventory/atomUtils.js +703 -43
- package/lib/inventory/auditCategories.js +7 -0
- package/lib/inventory/buildToolRateLimit.js +144 -0
- package/lib/inventory/cacheCommands.js +2 -1
- package/lib/inventory/cdxrs.js +103 -12
- package/lib/inventory/cmakeBuildDirs.js +254 -0
- package/lib/inventory/deps.js +501 -124
- package/lib/inventory/depsUtils.js +183 -11
- package/lib/inventory/display.js +4 -5
- package/lib/inventory/dosai.js +798 -57
- package/lib/inventory/dosaiParsers.js +310 -15
- package/lib/inventory/dynamic.js +90 -6
- package/lib/inventory/evidenceUtils.js +166 -113
- package/lib/inventory/fetchBatch.js +690 -55
- 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/protobom.js +8 -1
- package/lib/inventory/purl.js +152 -3
- package/lib/inventory/rustFormulationParser.js +3 -4
- package/lib/inventory/sbomDocument.js +2 -70
- package/lib/inventory/scalaCoords.js +153 -0
- package/lib/inventory/source.js +45 -27
- package/lib/inventory/spdx.js +101 -0
- package/lib/inventory/traceRunner.js +295 -25
- package/lib/inventory/tracedCrypto.js +294 -0
- package/lib/managers/binary.js +115 -24
- package/lib/managers/docker.js +467 -46
- package/lib/managers/oci.js +63 -3
- package/lib/parsers/cmakeCache.js +69 -0
- package/lib/parsers/cmakeLists.js +466 -0
- package/lib/parsers/cmakePresets.js +400 -0
- package/lib/parsers/compileCommands.js +557 -0
- package/lib/parsers/largeJson.js +454 -0
- package/lib/parsers/npmrc.js +19 -1
- 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 +83 -16
- package/lib/stages/postgen/specVersionCompat.js +32 -0
- package/lib/validator/bomValidator.js +6 -16
- package/lib/validator/index.js +64 -11
- package/lib/validator/reporters/console.js +3 -0
- package/lib/validator/reporters/json.js +2 -0
- package/lib/validator/reporters/sarif.js +7 -0
- package/package.json +23 -23
- package/types/lib/audit/index.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.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 +55 -0
- 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/metadataProperties.d.ts +39 -0
- package/types/lib/core/metadataProperties.d.ts.map +1 -0
- 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/projectConfig.d.ts +6 -2
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- 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 +12 -5
- 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/caxa.d.ts +14 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -1
- package/types/lib/ecosystems/cmakeResolver.d.ts +28 -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 +17 -1
- 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 +70 -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 +13 -0
- package/types/lib/ecosystems/kosi.d.ts.map +1 -1
- package/types/lib/ecosystems/npmutils.d.ts +57 -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 +54 -2
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +16 -5
- 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 +70 -4
- 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-rust.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 +164 -3
- 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/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 +132 -15
- 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/bomSigner.d.ts +182 -13
- 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 +219 -5
- 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/cdxrs.d.ts +8 -3
- package/types/lib/inventory/cdxrs.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/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 +121 -9
- 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/plugins.d.ts.map +1 -1
- package/types/lib/inventory/protobom.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/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/sbomDocument.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 +59 -1
- 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/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 +17 -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 +77 -0
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
- 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/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/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/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +18 -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
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
|
-
import {
|
|
2
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { delimiter, dirname, join } from "node:path";
|
|
4
5
|
|
|
5
6
|
import { Purl } from "@cdxgen/cdx-purl";
|
|
6
7
|
|
|
7
|
-
import { DEBUG_MODE } from "../core/activity.js";
|
|
8
|
+
import { DEBUG_MODE, readEnvironmentVariable } from "../core/activity.js";
|
|
8
9
|
import { shouldFetchLicense, shouldFetchVCS } from "../core/env.js";
|
|
9
|
-
import { safeExistsSync } from "../core/fs.js";
|
|
10
|
-
import { applyPurl, tryBuildPurl, tryParsePurl } from "../inventory/purl.js";
|
|
11
10
|
import {
|
|
12
|
-
|
|
11
|
+
applyPurl,
|
|
12
|
+
canonicalPurlFromLooseString,
|
|
13
|
+
tryBuildPurl,
|
|
14
|
+
tryParsePurl,
|
|
15
|
+
} from "../inventory/purl.js";
|
|
16
|
+
import { guessLicenseId } from "../inventory/spdx.js";
|
|
17
|
+
import {
|
|
13
18
|
getGoPkgLicense,
|
|
14
19
|
getGoPkgVCSUrl,
|
|
15
20
|
prefetchGoPkgMetadata,
|
|
@@ -25,6 +30,163 @@ function toBase64(hexString) {
|
|
|
25
30
|
return Buffer.from(hexString, "hex").toString("base64");
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
/**
|
|
34
|
+
* The root of the Go module cache on this machine.
|
|
35
|
+
*
|
|
36
|
+
* @returns {string|undefined} `$GOMODCACHE`, or `$GOPATH/pkg/mod`, or the
|
|
37
|
+
* default `~/go/pkg/mod`.
|
|
38
|
+
*/
|
|
39
|
+
function goModuleCacheDir() {
|
|
40
|
+
const gomodcache = readEnvironmentVariable("GOMODCACHE");
|
|
41
|
+
if (gomodcache) {
|
|
42
|
+
return gomodcache;
|
|
43
|
+
}
|
|
44
|
+
const gopath = readEnvironmentVariable("GOPATH");
|
|
45
|
+
if (gopath) {
|
|
46
|
+
return join(gopath.split(delimiter)[0], "pkg", "mod");
|
|
47
|
+
}
|
|
48
|
+
return join(homedir(), "go", "pkg", "mod");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Escape a module path the way Go's module cache directory names do: every
|
|
53
|
+
* upper-case letter becomes `!` followed by the lower-case one, so the cache
|
|
54
|
+
* stays case-preserving on case-insensitive file systems
|
|
55
|
+
* (`github.com/Azure` is stored as `github.com/!azure`).
|
|
56
|
+
*
|
|
57
|
+
* @param {string} modulePath Full module path
|
|
58
|
+
* @returns {string} The escaped path
|
|
59
|
+
*/
|
|
60
|
+
function escapeGoModulePath(modulePath) {
|
|
61
|
+
let escaped = "";
|
|
62
|
+
for (const ch of modulePath) {
|
|
63
|
+
if (ch >= "A" && ch <= "Z") {
|
|
64
|
+
escaped += `!${ch.toLowerCase()}`;
|
|
65
|
+
} else {
|
|
66
|
+
escaped += ch;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return escaped;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Whether a file name is a licence or copying notice, whose text describes the
|
|
74
|
+
* module's licence without a registry round.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} fileName Candidate file name
|
|
77
|
+
* @returns {boolean}
|
|
78
|
+
*/
|
|
79
|
+
function isGoLicenseFileName(fileName) {
|
|
80
|
+
const lower = fileName.toLowerCase();
|
|
81
|
+
return lower.startsWith("license") || lower.startsWith("copying");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The licence or copying notice of a module that is already on this machine,
|
|
86
|
+
* from the directory `go list` reported, from the project's `vendor/` tree, or
|
|
87
|
+
* from the module cache. Reading it costs no network round trip, so it answers
|
|
88
|
+
* before pkg.go.dev is asked.
|
|
89
|
+
*
|
|
90
|
+
* The directory `go list` reported is always read. The vendor tree and the
|
|
91
|
+
* module cache stand in for pkg.go.dev, so they are read only when licences
|
|
92
|
+
* are being fetched.
|
|
93
|
+
*
|
|
94
|
+
* @param {string} name Full module path
|
|
95
|
+
* @param {string} [version] Module version, for the module cache layout
|
|
96
|
+
* @param {Object} [options] Options
|
|
97
|
+
* @param {string} [options.dir] The module's directory, as `go list` reports it
|
|
98
|
+
* @param {string} [options.projectRoot] Project root holding a `vendor/` tree
|
|
99
|
+
* @returns {string|undefined} The notice text, or undefined when none is held
|
|
100
|
+
* locally
|
|
101
|
+
*/
|
|
102
|
+
export function readLocalGoLicense(name, version, options = {}) {
|
|
103
|
+
if (!name) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
const candidateDirs = [];
|
|
107
|
+
if (options.dir) {
|
|
108
|
+
candidateDirs.push(options.dir);
|
|
109
|
+
}
|
|
110
|
+
const fetchingLicenses = shouldFetchLicense();
|
|
111
|
+
if (fetchingLicenses && options.projectRoot) {
|
|
112
|
+
candidateDirs.push(join(options.projectRoot, "vendor", name));
|
|
113
|
+
}
|
|
114
|
+
if (fetchingLicenses && version) {
|
|
115
|
+
const cacheRoot = goModuleCacheDir();
|
|
116
|
+
if (cacheRoot) {
|
|
117
|
+
candidateDirs.push(
|
|
118
|
+
join(cacheRoot, `${escapeGoModulePath(name)}@${version}`),
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const dir of candidateDirs) {
|
|
123
|
+
let entries;
|
|
124
|
+
try {
|
|
125
|
+
entries = readdirSync(dir);
|
|
126
|
+
} catch {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const names = entries
|
|
130
|
+
.filter((e) => isGoLicenseFileName(e))
|
|
131
|
+
.sort((a, b) => a.localeCompare(b));
|
|
132
|
+
// A directory can hold both a licence and a copying notice; the licence
|
|
133
|
+
// notice wins when both are present.
|
|
134
|
+
const chosen =
|
|
135
|
+
names.find((f) => f.toLowerCase().startsWith("license")) ||
|
|
136
|
+
names.find((f) => f.toLowerCase().startsWith("copying"));
|
|
137
|
+
if (!chosen) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const text = readFileSync(join(dir, chosen), {
|
|
142
|
+
encoding: "utf-8",
|
|
143
|
+
});
|
|
144
|
+
if (text?.length) {
|
|
145
|
+
return text;
|
|
146
|
+
}
|
|
147
|
+
} catch {
|
|
148
|
+
// An unreadable notice is the same as none: the registry path answers.
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Mark the modules whose licence notice is held on this machine, so the
|
|
156
|
+
* pkg.go.dev batch skips their licence tab but still fetches their module page
|
|
157
|
+
* for the repository URL.
|
|
158
|
+
*
|
|
159
|
+
* @param {Object[]} modules Modules with `name`, `version` and the options
|
|
160
|
+
* {@link readLocalGoLicense} takes
|
|
161
|
+
* @returns {Object[]} Copies of the modules with `licenseKnown` set
|
|
162
|
+
*/
|
|
163
|
+
function withLocalLicenseFlags(modules) {
|
|
164
|
+
return modules.map((m) => ({
|
|
165
|
+
...m,
|
|
166
|
+
licenseKnown: !!readLocalGoLicense(m.name, m.version, m),
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The licence object for a notice read from disk: its SPDX id when the text
|
|
172
|
+
* names one, else a CUSTOM licence, with the notice as its text either way.
|
|
173
|
+
*
|
|
174
|
+
* @param {string} text Notice text
|
|
175
|
+
* @returns {Object} CycloneDX licence object
|
|
176
|
+
*/
|
|
177
|
+
function localGoLicenseObject(text) {
|
|
178
|
+
const licenseId = guessLicenseId(text);
|
|
179
|
+
const identity = !licenseId
|
|
180
|
+
? { name: "CUSTOM" }
|
|
181
|
+
: licenseId.includes(" ")
|
|
182
|
+
? { name: licenseId }
|
|
183
|
+
: { id: licenseId };
|
|
184
|
+
return {
|
|
185
|
+
...identity,
|
|
186
|
+
text: { contentType: "text/plain", content: text },
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
28
190
|
/**
|
|
29
191
|
* Builds a Go package component object containing purl, bom-ref, integrity hash,
|
|
30
192
|
* and optionally license and VCS external reference information.
|
|
@@ -33,11 +195,31 @@ function toBase64(hexString) {
|
|
|
33
195
|
* @param {string} name Package name (full module path when group is empty)
|
|
34
196
|
* @param {string} version Package version string
|
|
35
197
|
* @param {string} hash Integrity hash (e.g. "sha256-…"), used as _integrity
|
|
198
|
+
* @param {Object} [options] Options
|
|
199
|
+
* @param {boolean} [options.skipRegistryLookups] Leave the licence and VCS
|
|
200
|
+
* URL unset instead of asking pkg.go.dev. Used for the main module, which
|
|
201
|
+
* no registry holds.
|
|
202
|
+
* @param {string} [options.dir] The module's directory, as `go list` reports
|
|
203
|
+
* it, where a local licence notice is read first
|
|
204
|
+
* @param {string} [options.projectRoot] Project root holding a `vendor/` tree
|
|
205
|
+
* the module may be vendored in
|
|
36
206
|
* @returns {Promise<Object>} Component object ready for inclusion in a BOM package list
|
|
37
207
|
*/
|
|
38
|
-
export async function getGoPkgComponent(
|
|
208
|
+
export async function getGoPkgComponent(
|
|
209
|
+
group,
|
|
210
|
+
name,
|
|
211
|
+
version,
|
|
212
|
+
hash,
|
|
213
|
+
options = {},
|
|
214
|
+
) {
|
|
39
215
|
let license;
|
|
40
|
-
|
|
216
|
+
let licenses;
|
|
217
|
+
// A notice held on this machine answers before pkg.go.dev is asked, and the
|
|
218
|
+
// registry is consulted only when there is none.
|
|
219
|
+
const localLicense = readLocalGoLicense(name, version, options);
|
|
220
|
+
if (localLicense) {
|
|
221
|
+
licenses = [{ license: localGoLicenseObject(localLicense) }];
|
|
222
|
+
} else if (shouldFetchLicense() && !options.skipRegistryLookups) {
|
|
41
223
|
if (DEBUG_MODE) {
|
|
42
224
|
console.log(
|
|
43
225
|
`About to fetch go package license information for ${group}:${name}`,
|
|
@@ -46,6 +228,7 @@ export async function getGoPkgComponent(group, name, version, hash) {
|
|
|
46
228
|
license = await getGoPkgLicense({
|
|
47
229
|
group: group,
|
|
48
230
|
name: name,
|
|
231
|
+
version: version,
|
|
49
232
|
});
|
|
50
233
|
}
|
|
51
234
|
// Split the full module path into namespace and name, since the caller
|
|
@@ -71,8 +254,8 @@ export async function getGoPkgComponent(group, name, version, hash) {
|
|
|
71
254
|
version: version || null,
|
|
72
255
|
})?.replace(/%2F/g, "/") || null;
|
|
73
256
|
let vcs;
|
|
74
|
-
if (shouldFetchVCS()) {
|
|
75
|
-
vcs = await getGoPkgVCSUrl(group, name);
|
|
257
|
+
if (shouldFetchVCS() && !options.skipRegistryLookups) {
|
|
258
|
+
vcs = await getGoPkgVCSUrl(group, name, version);
|
|
76
259
|
}
|
|
77
260
|
const packageInfo = {
|
|
78
261
|
group: group,
|
|
@@ -81,6 +264,9 @@ export async function getGoPkgComponent(group, name, version, hash) {
|
|
|
81
264
|
_integrity: hash,
|
|
82
265
|
license: license,
|
|
83
266
|
};
|
|
267
|
+
if (licenses) {
|
|
268
|
+
packageInfo.licenses = licenses;
|
|
269
|
+
}
|
|
84
270
|
applyPurl(packageInfo, purlString);
|
|
85
271
|
if (vcs) {
|
|
86
272
|
packageInfo.externalReferences = [{ type: "vcs", url: vcs }];
|
|
@@ -104,7 +290,9 @@ export async function parseGoModData(goModData, gosumMap) {
|
|
|
104
290
|
return {};
|
|
105
291
|
}
|
|
106
292
|
const { parentComponent, entries } = decodeGoModData(goModData, gosumMap);
|
|
107
|
-
|
|
293
|
+
// A module whose licence notice is read locally is not asked for its
|
|
294
|
+
// licence; getGoPkgComponent reads the same notice for each entry below.
|
|
295
|
+
await prefetchGoPkgMetadata(withLocalLicenseFlags(entries));
|
|
108
296
|
for (const entry of entries) {
|
|
109
297
|
const component = await getGoPkgComponent(
|
|
110
298
|
"",
|
|
@@ -124,8 +312,6 @@ export async function parseGoModData(goModData, gosumMap) {
|
|
|
124
312
|
}
|
|
125
313
|
pkgComponentsList.push(component);
|
|
126
314
|
}
|
|
127
|
-
// Clear the cache
|
|
128
|
-
_clearMetadataCache();
|
|
129
315
|
return {
|
|
130
316
|
parentComponent,
|
|
131
317
|
pkgList: pkgComponentsList.sort((a, b) =>
|
|
@@ -266,18 +452,30 @@ export async function parseGoModulesTxt(txtFile, gosumMap) {
|
|
|
266
452
|
const pkgs = txtData
|
|
267
453
|
.split("\n")
|
|
268
454
|
.filter((p) => p.trim().replace(/["']/g, "").startsWith("# "));
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
)
|
|
273
|
-
for (const l of pkgs) {
|
|
455
|
+
// A modules.txt file lives in the vendor/ tree, so the modules it lists are
|
|
456
|
+
// vendored one directory up from it.
|
|
457
|
+
const projectRoot = dirname(dirname(txtFile));
|
|
458
|
+
const modules = pkgs.map((l) => {
|
|
274
459
|
const tmpA = l.split(" ");
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
460
|
+
return {
|
|
461
|
+
group: "",
|
|
462
|
+
name: tmpA[1],
|
|
463
|
+
version: tmpA[2],
|
|
464
|
+
projectRoot,
|
|
465
|
+
};
|
|
466
|
+
});
|
|
467
|
+
// A module whose vendored licence notice is read is not asked for its
|
|
468
|
+
// licence; getGoPkgComponent reads the same file.
|
|
469
|
+
await prefetchGoPkgMetadata(withLocalLicenseFlags(modules));
|
|
470
|
+
for (const m of modules) {
|
|
471
|
+
const gosumHash = gosumMap[`${m.name}@${m.version}`];
|
|
472
|
+
const component = await getGoPkgComponent(
|
|
473
|
+
"",
|
|
474
|
+
m.name,
|
|
475
|
+
m.version,
|
|
476
|
+
gosumHash,
|
|
477
|
+
{ projectRoot },
|
|
478
|
+
);
|
|
281
479
|
let confidence = 0.7;
|
|
282
480
|
if (gosumHash) {
|
|
283
481
|
component.scope = "required";
|
|
@@ -308,19 +506,44 @@ export async function parseGoListDep(rawOutput, gosumMap) {
|
|
|
308
506
|
// covers every module the loop resolves and nothing else.
|
|
309
507
|
const prefetchSeen = new Set();
|
|
310
508
|
const prefetchModules = [];
|
|
509
|
+
// The directory of the main module row, which is the project root, under
|
|
510
|
+
// which the vendored copies of the dependencies live. `go list` may print
|
|
511
|
+
// the main module last, so its row is found before the batch is built.
|
|
512
|
+
let mainModuleDir;
|
|
513
|
+
for (const l of pkgs) {
|
|
514
|
+
const verArr = l.trim().replace(/["']/g, "").split("|");
|
|
515
|
+
if (verArr?.length >= 10 && verArr[5] === "true" && verArr[9]?.length) {
|
|
516
|
+
mainModuleDir = verArr[9];
|
|
517
|
+
}
|
|
518
|
+
}
|
|
311
519
|
for (const l of pkgs) {
|
|
312
520
|
const verArr = l.trim().replace(/["']/g, "").split("|");
|
|
313
521
|
if (!verArr || verArr.length < 5) {
|
|
314
522
|
continue;
|
|
315
523
|
}
|
|
524
|
+
// The row whose fifth field is true is the main module: the project
|
|
525
|
+
// itself, which no registry holds and which the loop below turns into
|
|
526
|
+
// the parent component.
|
|
527
|
+
if (verArr[5] === "true") {
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
316
530
|
const key = `${verArr[0]}-${verArr[1]}`;
|
|
317
531
|
if (prefetchSeen.has(key)) {
|
|
318
532
|
continue;
|
|
319
533
|
}
|
|
320
534
|
prefetchSeen.add(key);
|
|
321
|
-
prefetchModules.push({
|
|
535
|
+
prefetchModules.push({
|
|
536
|
+
group: "",
|
|
537
|
+
name: verArr[0],
|
|
538
|
+
version: verArr[1],
|
|
539
|
+
dir: verArr[9]?.length ? verArr[9] : undefined,
|
|
540
|
+
projectRoot: mainModuleDir,
|
|
541
|
+
});
|
|
322
542
|
}
|
|
323
|
-
|
|
543
|
+
// A module whose licence notice is held on this machine is not asked for
|
|
544
|
+
// its licence: getGoPkgComponent reads the same notices, so the batch
|
|
545
|
+
// covers exactly what the loop will look up.
|
|
546
|
+
await prefetchGoPkgMetadata(withLocalLicenseFlags(prefetchModules));
|
|
324
547
|
for (const l of pkgs) {
|
|
325
548
|
const verArr = l.trim().replace(/["']/g, "").split("|");
|
|
326
549
|
if (verArr && verArr.length >= 5) {
|
|
@@ -333,11 +556,17 @@ export async function parseGoListDep(rawOutput, gosumMap) {
|
|
|
333
556
|
if (!gosumHash && verArr.length >= 8 && verArr[8]?.length) {
|
|
334
557
|
gosumHash = `sha256-${verArr[8].replace("h1:", "")}`;
|
|
335
558
|
}
|
|
559
|
+
const isMainModule = verArr[5] === "true";
|
|
336
560
|
const component = await getGoPkgComponent(
|
|
337
561
|
"",
|
|
338
562
|
verArr[0],
|
|
339
563
|
version,
|
|
340
564
|
gosumHash,
|
|
565
|
+
{
|
|
566
|
+
skipRegistryLookups: isMainModule,
|
|
567
|
+
dir: verArr[9]?.length ? verArr[9] : undefined,
|
|
568
|
+
projectRoot: mainModuleDir,
|
|
569
|
+
},
|
|
341
570
|
);
|
|
342
571
|
// This is misusing the scope attribute to represent direct vs indirect
|
|
343
572
|
if (verArr[2] === "false") {
|
|
@@ -380,21 +609,6 @@ export async function parseGoListDep(rawOutput, gosumMap) {
|
|
|
380
609
|
name: "cdx:go:local_dir",
|
|
381
610
|
value: verArr[9],
|
|
382
611
|
});
|
|
383
|
-
if (safeExistsSync(join(verArr[9], "LICENSE"))) {
|
|
384
|
-
const licenseText = readFileSync(join(verArr[9], "LICENSE"), {
|
|
385
|
-
encoding: "utf-8",
|
|
386
|
-
});
|
|
387
|
-
if (licenseText?.length) {
|
|
388
|
-
component.licenses = [
|
|
389
|
-
{
|
|
390
|
-
license: {
|
|
391
|
-
name: "CUSTOM",
|
|
392
|
-
text: { contentType: "text/plain", content: licenseText },
|
|
393
|
-
},
|
|
394
|
-
},
|
|
395
|
-
];
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
612
|
}
|
|
399
613
|
if (verArr.length > 5 && verArr[5] === "true") {
|
|
400
614
|
parentComponent = component;
|
|
@@ -443,6 +657,23 @@ function _addGoComponentEvidence(component, goModFile, confidence = 0.8) {
|
|
|
443
657
|
return component;
|
|
444
658
|
}
|
|
445
659
|
|
|
660
|
+
/**
|
|
661
|
+
* Build the purl of one `module@version` token from `go mod graph` output.
|
|
662
|
+
*
|
|
663
|
+
* The version is written the way Go prints it, so `+incompatible` and the build
|
|
664
|
+
* metadata of a pseudo-version are unescaped. Reading the token strictly would
|
|
665
|
+
* reject it and leave a reference that keeps the module path's upper-case
|
|
666
|
+
* letters, which then never matches the lower-cased component and drops the
|
|
667
|
+
* dependency edge.
|
|
668
|
+
*
|
|
669
|
+
* @param {string} token Module path, optionally followed by `@version`
|
|
670
|
+
* @returns {Purl|null} Parsed purl, or null when the token forms no valid golang purl
|
|
671
|
+
*/
|
|
672
|
+
function goModGraphTokenPurl(token) {
|
|
673
|
+
const canonical = canonicalPurlFromLooseString(`pkg:golang/${token}`);
|
|
674
|
+
return canonical ? Purl.parse(canonical) : null;
|
|
675
|
+
}
|
|
676
|
+
|
|
446
677
|
/**
|
|
447
678
|
* Parse go mod graph
|
|
448
679
|
*
|
|
@@ -512,22 +743,20 @@ export async function parseGoModGraph(
|
|
|
512
743
|
// cdx-purl requires a namespace. Use the raw ref when parsing fails.
|
|
513
744
|
let sourceRefString;
|
|
514
745
|
let sourceName = tmpA[0].split("@")[0];
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
sourcePurl = Purl.parse(`pkg:golang/${tmpA[0]}`);
|
|
746
|
+
const sourcePurl = goModGraphTokenPurl(tmpA[0]);
|
|
747
|
+
if (sourcePurl) {
|
|
518
748
|
sourceRefString = decodeURIComponent(sourcePurl.toString());
|
|
519
749
|
sourceName = `${sourcePurl.namespace ? `${sourcePurl.namespace}/` : ""}${sourcePurl.name}`;
|
|
520
|
-
}
|
|
750
|
+
} else {
|
|
521
751
|
sourceRefString = `pkg:golang/${tmpA[0]}`;
|
|
522
752
|
}
|
|
523
753
|
let dependsRefString;
|
|
524
754
|
let dependsName = tmpA[1].split("@")[0];
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
dependsPurl = Purl.parse(`pkg:golang/${tmpA[1]}`);
|
|
755
|
+
const dependsPurl = goModGraphTokenPurl(tmpA[1]);
|
|
756
|
+
if (dependsPurl) {
|
|
528
757
|
dependsRefString = decodeURIComponent(dependsPurl.toString());
|
|
529
758
|
dependsName = `${dependsPurl.namespace ? `${dependsPurl.namespace}/` : ""}${dependsPurl.name}`;
|
|
530
|
-
}
|
|
759
|
+
} else {
|
|
531
760
|
dependsRefString = `pkg:golang/${tmpA[1]}`;
|
|
532
761
|
}
|
|
533
762
|
// Since go mod graph over-reports direct dependencies we use the existing list
|
|
@@ -542,11 +771,20 @@ export async function parseGoModGraph(
|
|
|
542
771
|
}
|
|
543
772
|
// Add the source and depends to the pkgList
|
|
544
773
|
if (!addedPkgs[tmpA[0]] && !excludedRefs.includes(sourceRefString)) {
|
|
774
|
+
// go mod graph prints a main module without a version. A main
|
|
775
|
+
// module is the project itself, or a go.work member, which no
|
|
776
|
+
// registry holds, so it is never looked up. It still becomes a
|
|
777
|
+
// component, because the graph's edges hang off it.
|
|
778
|
+
const isParentSource =
|
|
779
|
+
!tmpA[0].includes("@") ||
|
|
780
|
+
sourceName === goModPkgMap?.parentComponent?.name ||
|
|
781
|
+
sourceRefString === parentComponent?.["bom-ref"];
|
|
545
782
|
const component = await getGoPkgComponent(
|
|
546
783
|
"",
|
|
547
784
|
sourceName,
|
|
548
785
|
sourcePurl?.version || tmpA[0].split("@")[1],
|
|
549
786
|
gosumMap[tmpA[0]],
|
|
787
|
+
{ skipRegistryLookups: isParentSource },
|
|
550
788
|
);
|
|
551
789
|
let confidence = 0.7;
|
|
552
790
|
if (goModOptionalDepsMap[component["bom-ref"]]) {
|
|
@@ -684,19 +922,49 @@ export function parseGoModWhy(rawOutput) {
|
|
|
684
922
|
}
|
|
685
923
|
|
|
686
924
|
/**
|
|
687
|
-
*
|
|
925
|
+
* Reports whether `go mod why -m` output says the main module does not need
|
|
926
|
+
* the module. go prints `(main module does not need module X)`, or
|
|
927
|
+
* `(main module does not need to vendor module X)` with `-vendor`, and exits
|
|
928
|
+
* with status 0 either way.
|
|
929
|
+
*
|
|
930
|
+
* @param {string} rawOutput Output from go mod why
|
|
931
|
+
* @returns {boolean} True when go reports the module as not needed
|
|
932
|
+
*/
|
|
933
|
+
export function isGoModWhyNotNeeded(rawOutput) {
|
|
934
|
+
if (typeof rawOutput !== "string") {
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
937
|
+
return rawOutput
|
|
938
|
+
.split("\n")
|
|
939
|
+
.some((line) => line.trim().startsWith("(main module does not need "));
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/**
|
|
943
|
+
* Read the `module@version` to hash map out of go.sum contents, without
|
|
944
|
+
* building components or touching the network.
|
|
945
|
+
*
|
|
688
946
|
* @param {string} gosumData Content of go.sum
|
|
689
|
-
* @returns
|
|
947
|
+
* @returns {Object} Map of `module@version` keys to `sha256-…` values
|
|
690
948
|
*/
|
|
691
|
-
export
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
|
|
949
|
+
export function parseGosumHashes(gosumData) {
|
|
950
|
+
const gosumMap = {};
|
|
951
|
+
for (const entry of decodeGosumData(gosumData)) {
|
|
952
|
+
gosumMap[`${entry.name}@${entry.version}`] = entry.hash;
|
|
695
953
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
954
|
+
return gosumMap;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* Decode the go.mod lines of a go.sum file into module entries.
|
|
959
|
+
*
|
|
960
|
+
* @param {string} gosumData Content of go.sum
|
|
961
|
+
* @returns {Object[]} Entries with `name`, `version` and `hash`
|
|
962
|
+
*/
|
|
963
|
+
function decodeGosumData(gosumData) {
|
|
699
964
|
const entries = [];
|
|
965
|
+
if (!gosumData) {
|
|
966
|
+
return entries;
|
|
967
|
+
}
|
|
700
968
|
for (const l of gosumData.split("\n")) {
|
|
701
969
|
const m = l.replaceAll("\r", "");
|
|
702
970
|
// look for lines containing go.mod
|
|
@@ -710,7 +978,20 @@ export async function parseGosumData(gosumData) {
|
|
|
710
978
|
});
|
|
711
979
|
}
|
|
712
980
|
}
|
|
713
|
-
|
|
981
|
+
return entries;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* Parse go sum data
|
|
986
|
+
* @param {string} gosumData Content of go.sum
|
|
987
|
+
* @returns package list
|
|
988
|
+
*/
|
|
989
|
+
export async function parseGosumData(gosumData) {
|
|
990
|
+
const pkgList = [];
|
|
991
|
+
const entries = decodeGosumData(gosumData);
|
|
992
|
+
// A module whose licence notice is read locally is not asked for its
|
|
993
|
+
// licence; getGoPkgComponent reads the same notice for each entry below.
|
|
994
|
+
await prefetchGoPkgMetadata(withLocalLicenseFlags(entries));
|
|
714
995
|
for (const entry of entries) {
|
|
715
996
|
pkgList.push(
|
|
716
997
|
await getGoPkgComponent("", entry.name, entry.version, entry.hash),
|
|
@@ -737,13 +1018,17 @@ export async function parseGopkgData(gopkgData) {
|
|
|
737
1018
|
for (const l of pkgs) {
|
|
738
1019
|
let key = null;
|
|
739
1020
|
let value = null;
|
|
740
|
-
|
|
1021
|
+
// Every table header ends the project read so far, and only a
|
|
1022
|
+
// [[projects]] table starts another. The keys of [solve-meta] belong to
|
|
1023
|
+
// no project.
|
|
1024
|
+
if (l.trim().startsWith("[")) {
|
|
741
1025
|
if (pkg) {
|
|
742
|
-
pkgList.push(pkg);
|
|
1026
|
+
pkgList.push(await finalizeGopkgProject(pkg));
|
|
743
1027
|
}
|
|
744
|
-
pkg = {};
|
|
1028
|
+
pkg = l.indexOf("[[projects]]") > -1 ? {} : null;
|
|
1029
|
+
continue;
|
|
745
1030
|
}
|
|
746
|
-
if (l.indexOf("=") > -1) {
|
|
1031
|
+
if (pkg && l.indexOf("=") > -1) {
|
|
747
1032
|
const tmpA = l.split("=");
|
|
748
1033
|
key = tmpA[0].trim();
|
|
749
1034
|
value = tmpA[1].trim().replace(/"/g, "");
|
|
@@ -756,12 +1041,6 @@ export async function parseGopkgData(gopkgData) {
|
|
|
756
1041
|
case "name":
|
|
757
1042
|
pkg.group = "";
|
|
758
1043
|
pkg.name = value;
|
|
759
|
-
if (shouldFetchLicense()) {
|
|
760
|
-
pkg.license = await getGoPkgLicense({
|
|
761
|
-
group: pkg.group,
|
|
762
|
-
name: pkg.name,
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
1044
|
break;
|
|
766
1045
|
case "version":
|
|
767
1046
|
pkg.version = value;
|
|
@@ -773,9 +1052,31 @@ export async function parseGopkgData(gopkgData) {
|
|
|
773
1052
|
}
|
|
774
1053
|
}
|
|
775
1054
|
}
|
|
1055
|
+
// The last project has no header after it.
|
|
1056
|
+
if (pkg) {
|
|
1057
|
+
pkgList.push(await finalizeGopkgProject(pkg));
|
|
1058
|
+
}
|
|
776
1059
|
return pkgList;
|
|
777
1060
|
}
|
|
778
1061
|
|
|
1062
|
+
/**
|
|
1063
|
+
* Attach the licence of one Gopkg project once its name and version are both
|
|
1064
|
+
* known, so the pkg.go.dev URL names the pinned release.
|
|
1065
|
+
*
|
|
1066
|
+
* @param {Object} pkg The project entry read so far
|
|
1067
|
+
* @returns {Promise<Object>} The same entry, with a licence when one was found
|
|
1068
|
+
*/
|
|
1069
|
+
async function finalizeGopkgProject(pkg) {
|
|
1070
|
+
if (shouldFetchLicense() && pkg.name) {
|
|
1071
|
+
pkg.license = await getGoPkgLicense({
|
|
1072
|
+
group: pkg.group,
|
|
1073
|
+
name: pkg.name,
|
|
1074
|
+
version: pkg.version,
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
return pkg;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
779
1080
|
/**
|
|
780
1081
|
* Parses the output of `go version -m` (build info) and returns a list of Go
|
|
781
1082
|
* package components for each "dep" line, including name, version, and integrity hash.
|
|
@@ -808,7 +1109,7 @@ export async function parseGoVersionData(buildInfoData) {
|
|
|
808
1109
|
: "",
|
|
809
1110
|
});
|
|
810
1111
|
}
|
|
811
|
-
await prefetchGoPkgMetadata(entries);
|
|
1112
|
+
await prefetchGoPkgMetadata(withLocalLicenseFlags(entries));
|
|
812
1113
|
for (const entry of entries) {
|
|
813
1114
|
pkgList.push(
|
|
814
1115
|
await getGoPkgComponent("", entry.name, entry.version, entry.hash),
|