@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
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
loadNpmrcConfig,
|
|
32
32
|
normalizePnpmLockKey,
|
|
33
33
|
parsePnpmGitLockKey,
|
|
34
|
+
resolveNpmLicense,
|
|
34
35
|
setNpmDevelopmentProperty,
|
|
35
36
|
setNpmOptionalProperty,
|
|
36
37
|
setNpmPeerProperty,
|
|
@@ -135,6 +136,11 @@ const NPM_LIFECYCLE_JS_SOURCE_FILE_PATTERN = /\.[cm]?[jt]sx?$/i;
|
|
|
135
136
|
|
|
136
137
|
const SHELL_ENV_ASSIGNMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*=.*/;
|
|
137
138
|
|
|
139
|
+
// The root component's name when neither package.json, --project-name, nor
|
|
140
|
+
// the directory names one (a tree rooted at a file-system root): a purl needs
|
|
141
|
+
// a name.
|
|
142
|
+
const UNNAMED_NPM_PROJECT = "unnamed-project";
|
|
143
|
+
|
|
138
144
|
function splitLifecycleScriptCommands(scriptValue) {
|
|
139
145
|
const commands = [];
|
|
140
146
|
let current = "";
|
|
@@ -432,6 +438,9 @@ function analyzeNpmLifecycleScripts(pkgJsonFile, scripts) {
|
|
|
432
438
|
* identity evidence and skip npm registry metadata fetching.
|
|
433
439
|
* @param {boolean} [securityProps=false] When true, append npm security-relevant
|
|
434
440
|
* properties such as lifecycle scripts, binaries, native addons, and deprecation notices.
|
|
441
|
+
* @param {Object} [options] Options
|
|
442
|
+
* @param {boolean} [options.fetchMetadata=true] When false, skip the npm
|
|
443
|
+
* registry round so that a caller can make one round for many manifests.
|
|
435
444
|
* @returns {Promise<Array<object>>} Parsed component list, enriched with npm
|
|
436
445
|
* registry metadata when available and not in simple mode.
|
|
437
446
|
*/
|
|
@@ -439,11 +448,15 @@ export async function parsePkgJson(
|
|
|
439
448
|
pkgJsonFile,
|
|
440
449
|
simple = false,
|
|
441
450
|
securityProps = false,
|
|
451
|
+
options = {},
|
|
442
452
|
) {
|
|
443
453
|
const pkgList = [];
|
|
444
454
|
if (safeExistsSync(pkgJsonFile)) {
|
|
445
455
|
try {
|
|
446
|
-
|
|
456
|
+
// npm and Node.js both accept a package.json that starts with a UTF-8 BOM
|
|
457
|
+
const pkgData = JSON.parse(
|
|
458
|
+
readFileSync(pkgJsonFile, "utf8").replace(/^\uFEFF/, ""),
|
|
459
|
+
);
|
|
447
460
|
const pkgIdentifier = parsePackageJsonName(pkgData.name);
|
|
448
461
|
let name = pkgIdentifier.fullName || pkgData.name;
|
|
449
462
|
if (!name && !pkgJsonFile.includes("node_modules")) {
|
|
@@ -471,7 +484,7 @@ export async function parsePkgJson(
|
|
|
471
484
|
purl: purl,
|
|
472
485
|
"bom-ref": decodeURIComponent(purl),
|
|
473
486
|
author: authorString,
|
|
474
|
-
license: pkgData
|
|
487
|
+
license: resolveNpmLicense(pkgData),
|
|
475
488
|
};
|
|
476
489
|
if (pkgData.homepage) {
|
|
477
490
|
apkg.homepage = { url: pkgData.homepage };
|
|
@@ -662,7 +675,12 @@ export async function parsePkgJson(
|
|
|
662
675
|
// continue regardless of error
|
|
663
676
|
}
|
|
664
677
|
}
|
|
665
|
-
if (
|
|
678
|
+
if (
|
|
679
|
+
!simple &&
|
|
680
|
+
options.fetchMetadata !== false &&
|
|
681
|
+
shouldFetchPackageMetadata() &&
|
|
682
|
+
pkgList?.length
|
|
683
|
+
) {
|
|
666
684
|
if (DEBUG_MODE) {
|
|
667
685
|
console.log(
|
|
668
686
|
`About to fetch npm registry metadata for ${pkgList.length} packages in parsePkgJson`,
|
|
@@ -899,6 +917,9 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
899
917
|
|
|
900
918
|
let pkg;
|
|
901
919
|
let purlString;
|
|
920
|
+
// The license the installed package.json declares, for a package whose
|
|
921
|
+
// lockfile entry carries none (see the spoofing check below).
|
|
922
|
+
let installedManifestLicense;
|
|
902
923
|
const author = nodePackage.author;
|
|
903
924
|
const authorString =
|
|
904
925
|
author instanceof Object
|
|
@@ -908,8 +929,18 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
908
929
|
: author;
|
|
909
930
|
if (node === rootNode) {
|
|
910
931
|
const projectGroup = options.projectGroup;
|
|
932
|
+
// A package.json without a name still installs, so the root of a deep
|
|
933
|
+
// tree can lack one: name the root component after its directory, the
|
|
934
|
+
// way the scans without node_modules already do, rather than fail to
|
|
935
|
+
// build its purl (issue 4440). A tree rooted at a file-system root has
|
|
936
|
+
// no directory name either, and neither has the --project-name the CLI
|
|
937
|
+
// derives from it.
|
|
911
938
|
const projectName =
|
|
912
|
-
"project-name" in options
|
|
939
|
+
("project-name" in options && options.projectName) ||
|
|
940
|
+
node.packageName ||
|
|
941
|
+
basename(node.path || "") ||
|
|
942
|
+
node.name ||
|
|
943
|
+
UNNAMED_NPM_PROJECT;
|
|
913
944
|
const projectVersion = options.projectVersion || node.version;
|
|
914
945
|
// A package.json need not declare a version, and npm installs without
|
|
915
946
|
// one, so the root of a lockfile can reach here with none. A purl carries
|
|
@@ -927,8 +958,7 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
927
958
|
pkg = {
|
|
928
959
|
author: authorString,
|
|
929
960
|
group: options.projectGroup || "",
|
|
930
|
-
name:
|
|
931
|
-
"project-name" in options ? options.projectName : node.packageName,
|
|
961
|
+
name: projectName,
|
|
932
962
|
version: options.projectVersion || node.version,
|
|
933
963
|
type: "application",
|
|
934
964
|
purl: purlString,
|
|
@@ -964,13 +994,19 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
964
994
|
});
|
|
965
995
|
}
|
|
966
996
|
} else {
|
|
997
|
+
// A package.json without a name installs as a file: or workspace
|
|
998
|
+
// dependency too, and arborist then has no packageName for it: such a
|
|
999
|
+
// package goes by the name its folder has in the tree, which is also
|
|
1000
|
+
// the name the edges into it carry (issue 4440).
|
|
1001
|
+
const packageName =
|
|
1002
|
+
node.packageName || node.name || basename(node.path || "");
|
|
967
1003
|
let namespace = "";
|
|
968
|
-
let name =
|
|
969
|
-
if (
|
|
970
|
-
const slashIndex =
|
|
1004
|
+
let name = packageName;
|
|
1005
|
+
if (packageName.startsWith("@")) {
|
|
1006
|
+
const slashIndex = packageName.indexOf("/");
|
|
971
1007
|
if (slashIndex > 0) {
|
|
972
|
-
namespace =
|
|
973
|
-
name =
|
|
1008
|
+
namespace = packageName.substring(0, slashIndex);
|
|
1009
|
+
name = packageName.substring(slashIndex + 1);
|
|
974
1010
|
}
|
|
975
1011
|
}
|
|
976
1012
|
let qualifiers = null;
|
|
@@ -1083,9 +1119,17 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1083
1119
|
});
|
|
1084
1120
|
}
|
|
1085
1121
|
if (node?.binPaths?.length) {
|
|
1122
|
+
// Absolute bin paths would leak the generating machine's home
|
|
1123
|
+
// directory into the SBOM and differ between checkouts, so they are
|
|
1124
|
+
// emitted relative to the project root the package was resolved from,
|
|
1125
|
+
// with forward slashes on every platform (issue 4467).
|
|
1086
1126
|
pkg.properties.push({
|
|
1087
1127
|
name: "cdx:npm:binPaths",
|
|
1088
|
-
value: node.binPaths
|
|
1128
|
+
value: node.binPaths
|
|
1129
|
+
.map((binPath) =>
|
|
1130
|
+
relative(srcFilePath, binPath).split(_sep).join("/"),
|
|
1131
|
+
)
|
|
1132
|
+
.join(", "),
|
|
1089
1133
|
});
|
|
1090
1134
|
}
|
|
1091
1135
|
if (nodePackage?.bin) {
|
|
@@ -1154,9 +1198,14 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1154
1198
|
try {
|
|
1155
1199
|
const onDiskPkg =
|
|
1156
1200
|
diskPkg || JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
1157
|
-
|
|
1201
|
+
// A package that declares no name on disk and none in the lockfile
|
|
1202
|
+
// (a nameless file: dependency) disagrees with nothing.
|
|
1203
|
+
if (
|
|
1204
|
+
(onDiskPkg.name || node.packageName) &&
|
|
1205
|
+
onDiskPkg.name !== node.packageName
|
|
1206
|
+
) {
|
|
1158
1207
|
console.warn(
|
|
1159
|
-
`\x1b[1;35mWARNING: Package name spoofing detected for ${
|
|
1208
|
+
`\x1b[1;35mWARNING: Package name spoofing detected for ${packageName}! Lockfile says ${node.packageName}, but disk says ${onDiskPkg.name}.\x1b[0m`,
|
|
1160
1209
|
);
|
|
1161
1210
|
if (onDiskPkg.name) {
|
|
1162
1211
|
pkg.properties.push({
|
|
@@ -1165,9 +1214,12 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1165
1214
|
});
|
|
1166
1215
|
}
|
|
1167
1216
|
}
|
|
1168
|
-
if (
|
|
1217
|
+
if (
|
|
1218
|
+
(onDiskPkg.version || node.version) &&
|
|
1219
|
+
onDiskPkg.version !== node.version
|
|
1220
|
+
) {
|
|
1169
1221
|
console.warn(
|
|
1170
|
-
`\x1b[1;35mWARNING: Package version spoofing detected for ${
|
|
1222
|
+
`\x1b[1;35mWARNING: Package version spoofing detected for ${packageName}! Lockfile says ${node.version}, but disk says ${onDiskPkg.version}.\x1b[0m`,
|
|
1171
1223
|
);
|
|
1172
1224
|
if (onDiskPkg.version) {
|
|
1173
1225
|
pkg.properties.push({
|
|
@@ -1176,6 +1228,17 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1176
1228
|
});
|
|
1177
1229
|
}
|
|
1178
1230
|
}
|
|
1231
|
+
// npm records only the modern `license` field in the lockfile, so a
|
|
1232
|
+
// package that declares the legacy `licenses` array (issue 4466) has
|
|
1233
|
+
// no license in the tree loaded from it. The installed manifest is
|
|
1234
|
+
// then the only local declaration, and only when it is the package
|
|
1235
|
+
// the lockfile describes.
|
|
1236
|
+
if (
|
|
1237
|
+
onDiskPkg.name === node.packageName &&
|
|
1238
|
+
onDiskPkg.version === node.version
|
|
1239
|
+
) {
|
|
1240
|
+
installedManifestLicense = resolveNpmLicense(onDiskPkg);
|
|
1241
|
+
}
|
|
1179
1242
|
} catch (_err) {
|
|
1180
1243
|
// ignore
|
|
1181
1244
|
}
|
|
@@ -1231,9 +1294,11 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1231
1294
|
pkg.description = nodePackage.description;
|
|
1232
1295
|
}
|
|
1233
1296
|
}
|
|
1234
|
-
|
|
1297
|
+
const npmLicense =
|
|
1298
|
+
resolveNpmLicense(nodePackage) || installedManifestLicense;
|
|
1299
|
+
if (npmLicense) {
|
|
1235
1300
|
// License will be overridden if shouldFetchLicense() is enabled
|
|
1236
|
-
pkg.license =
|
|
1301
|
+
pkg.license = npmLicense;
|
|
1237
1302
|
}
|
|
1238
1303
|
const deprecatedMessage = nodePackage?.deprecated;
|
|
1239
1304
|
if (deprecatedMessage) {
|
|
@@ -1607,7 +1672,7 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1607
1672
|
`About to fetch npm registry metadata for ${pkgList.length} packages in parsePkgLock`,
|
|
1608
1673
|
);
|
|
1609
1674
|
}
|
|
1610
|
-
pkgList = await getNpmMetadata(pkgList);
|
|
1675
|
+
pkgList = await getNpmMetadata(pkgList, undefined, { npmrcConfig });
|
|
1611
1676
|
return { pkgList, dependenciesList };
|
|
1612
1677
|
}
|
|
1613
1678
|
return {
|
|
@@ -2457,7 +2522,7 @@ export async function parseYarnLock(
|
|
|
2457
2522
|
`About to fetch npm registry metadata for ${pkgList.length} packages in parseYarnLock`,
|
|
2458
2523
|
);
|
|
2459
2524
|
}
|
|
2460
|
-
pkgList = await getNpmMetadata(pkgList);
|
|
2525
|
+
pkgList = await getNpmMetadata(pkgList, undefined, { npmrcConfig });
|
|
2461
2526
|
return {
|
|
2462
2527
|
pkgList,
|
|
2463
2528
|
dependenciesList,
|
|
@@ -2476,6 +2541,7 @@ export async function parseYarnLock(
|
|
|
2476
2541
|
*/
|
|
2477
2542
|
export async function parseNodeShrinkwrap(swFile) {
|
|
2478
2543
|
const pkgList = [];
|
|
2544
|
+
const npmrcConfig = loadNpmrcConfig(dirname(swFile));
|
|
2479
2545
|
if (safeExistsSync(swFile)) {
|
|
2480
2546
|
const lockData = JSON.parse(readFileSync(swFile, "utf8"));
|
|
2481
2547
|
const pkgKeys = Object.keys(lockData);
|
|
@@ -2534,7 +2600,7 @@ export async function parseNodeShrinkwrap(swFile) {
|
|
|
2534
2600
|
`About to fetch npm registry metadata for ${pkgList.length} packages in parseNodeShrinkwrap`,
|
|
2535
2601
|
);
|
|
2536
2602
|
}
|
|
2537
|
-
return await getNpmMetadata(pkgList);
|
|
2603
|
+
return await getNpmMetadata(pkgList, undefined, { npmrcConfig });
|
|
2538
2604
|
}
|
|
2539
2605
|
return pkgList;
|
|
2540
2606
|
}
|
|
@@ -2702,13 +2768,13 @@ export async function getVersionNumPnpm(depPkg, relativePath) {
|
|
|
2702
2768
|
: join(version.replaceAll("../", "packages/"), "package.json");
|
|
2703
2769
|
if (safeExistsSync(relativePkgJson)) {
|
|
2704
2770
|
const importedComponentObj = await parsePkgJson(relativePkgJson, true);
|
|
2705
|
-
version = importedComponentObj[0]
|
|
2771
|
+
version = importedComponentObj[0]?.version;
|
|
2706
2772
|
} else if (safeExistsSync(join(version, "package.json"))) {
|
|
2707
2773
|
const importedComponentObj = await parsePkgJson(
|
|
2708
2774
|
join(version, "package.json"),
|
|
2709
2775
|
true,
|
|
2710
2776
|
);
|
|
2711
|
-
version = importedComponentObj[0]
|
|
2777
|
+
version = importedComponentObj[0]?.version;
|
|
2712
2778
|
} else if (
|
|
2713
2779
|
safeExistsSync(join(version.replaceAll("../", ""), "package.json"))
|
|
2714
2780
|
) {
|
|
@@ -2716,7 +2782,7 @@ export async function getVersionNumPnpm(depPkg, relativePath) {
|
|
|
2716
2782
|
join(version.replaceAll("../", ""), "package.json"),
|
|
2717
2783
|
true,
|
|
2718
2784
|
);
|
|
2719
|
-
version = importedComponentObj[0]
|
|
2785
|
+
version = importedComponentObj[0]?.version;
|
|
2720
2786
|
}
|
|
2721
2787
|
} else {
|
|
2722
2788
|
// version: 3.0.1(ajv@8.14.0) or, under lockfile 5, 3.0.1_ajv@8.14.0
|
|
@@ -4125,7 +4191,7 @@ export async function parsePnpmLock(
|
|
|
4125
4191
|
`About to fetch npm registry metadata for ${pkgList.length} packages in parsePnpmLock`,
|
|
4126
4192
|
);
|
|
4127
4193
|
}
|
|
4128
|
-
pkgList = await getNpmMetadata(pkgList);
|
|
4194
|
+
pkgList = await getNpmMetadata(pkgList, undefined, { npmrcConfig });
|
|
4129
4195
|
return {
|
|
4130
4196
|
pkgList,
|
|
4131
4197
|
dependenciesList,
|
|
@@ -4155,7 +4221,7 @@ export async function parseBowerJson(bowerJsonFile) {
|
|
|
4155
4221
|
group: pkgIdentifier.scope || "",
|
|
4156
4222
|
version: pkgData.version || "",
|
|
4157
4223
|
description: pkgData.description || "",
|
|
4158
|
-
license: pkgData
|
|
4224
|
+
license: resolveNpmLicense(pkgData) || "",
|
|
4159
4225
|
properties: [
|
|
4160
4226
|
{
|
|
4161
4227
|
name: "internal:SrcFile",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import { parseToml } from "../core/toml.js";
|
|
5
4
|
import { tryBuildPurl } from "../inventory/purl.js";
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -260,7 +259,7 @@ const JULIA_STDLIBS = new Set([
|
|
|
260
259
|
*/
|
|
261
260
|
function readTomlFile(filePath) {
|
|
262
261
|
try {
|
|
263
|
-
return
|
|
262
|
+
return parseToml(readFileSync(filePath, "utf-8"));
|
|
264
263
|
} catch (error) {
|
|
265
264
|
console.warn(`Failed to parse ${filePath}: ${error.message}`);
|
|
266
265
|
return undefined;
|
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import {
|
|
1
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import {
|
|
3
|
+
basename,
|
|
4
|
+
dirname,
|
|
5
|
+
isAbsolute,
|
|
6
|
+
join,
|
|
7
|
+
relative,
|
|
8
|
+
resolve,
|
|
9
|
+
} from "node:path";
|
|
3
10
|
|
|
4
11
|
import { build } from "@cdxgen/cdx-purl";
|
|
5
12
|
import { parseEDNString } from "edn-data";
|
|
6
13
|
|
|
7
|
-
import { readEnvironmentVariable } from "../core/activity.js";
|
|
14
|
+
import { DEBUG_MODE, readEnvironmentVariable } from "../core/activity.js";
|
|
8
15
|
import { recordDegradation } from "../core/buildLedger.js";
|
|
9
16
|
import { includeMavenTestScope } from "../core/env.js";
|
|
17
|
+
import { safeExistsSync } from "../core/fs.js";
|
|
10
18
|
import { thoughtLog } from "../core/logger.js";
|
|
11
19
|
import { applyPurl } from "../inventory/purl.js";
|
|
20
|
+
import { parseScalaArtifact } from "../inventory/scalaCoords.js";
|
|
12
21
|
import { xml2js } from "../parsers/xml.js";
|
|
13
22
|
|
|
14
23
|
/**
|
|
@@ -173,6 +182,158 @@ export function parsePom(pomFile) {
|
|
|
173
182
|
return { isQuarkus, pomPurl, modules, properties, dependencies: deps };
|
|
174
183
|
}
|
|
175
184
|
|
|
185
|
+
/** Bound on the reactor walk. A pom's module list is untrusted input, so the
|
|
186
|
+
* walk cannot trust it to stay finite. */
|
|
187
|
+
const REACTOR_MODULE_LIMIT = 500;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Every pom file of the reactor an aggregator pom builds: its own modules,
|
|
191
|
+
* recursively through nested aggregators. A recursive dependency:tree run
|
|
192
|
+
* from the aggregator resolves all of them, so their own runs repeat it.
|
|
193
|
+
*
|
|
194
|
+
* A module entry names a directory relative to its pom, sometimes a direct
|
|
195
|
+
* path to a pom file. Entries that are absolute, or that climb out of the
|
|
196
|
+
* aggregator's directory, are ignored: the scan never listed them, and the
|
|
197
|
+
* walk must not follow a pom's pointers outside its own tree.
|
|
198
|
+
*
|
|
199
|
+
* @param {string} rootPom Path of the aggregator pom.
|
|
200
|
+
* @returns {Set<string>} Pom files of the reactor, excluding the aggregator.
|
|
201
|
+
*/
|
|
202
|
+
export function resolveReactorPomFiles(rootPom) {
|
|
203
|
+
const pomFiles = new Set();
|
|
204
|
+
const visited = new Set();
|
|
205
|
+
const rootDir = dirname(resolve(rootPom));
|
|
206
|
+
const queue = [resolve(rootPom)];
|
|
207
|
+
while (queue.length > 0 && pomFiles.size < REACTOR_MODULE_LIMIT) {
|
|
208
|
+
const pom = queue.shift();
|
|
209
|
+
if (visited.has(pom)) {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
visited.add(pom);
|
|
213
|
+
let modules;
|
|
214
|
+
try {
|
|
215
|
+
modules = parsePom(pom)?.modules;
|
|
216
|
+
} catch (_err) {
|
|
217
|
+
// An unreadable module pom ends this branch of the walk.
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
for (const module of modules || []) {
|
|
221
|
+
if (typeof module !== "string") {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
const cleaned = module.trim().replaceAll("\\", "/");
|
|
225
|
+
if (
|
|
226
|
+
!cleaned ||
|
|
227
|
+
cleaned.includes("\0") ||
|
|
228
|
+
cleaned.startsWith("/") ||
|
|
229
|
+
/^[A-Za-z]:/.test(cleaned)
|
|
230
|
+
) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const modulePom = resolve(
|
|
234
|
+
dirname(pom),
|
|
235
|
+
cleaned.endsWith(".xml") ? cleaned : join(cleaned, "pom.xml"),
|
|
236
|
+
);
|
|
237
|
+
const withinRoot = relative(rootDir, modulePom);
|
|
238
|
+
if (
|
|
239
|
+
!withinRoot ||
|
|
240
|
+
withinRoot.startsWith("..") ||
|
|
241
|
+
isAbsolute(withinRoot) ||
|
|
242
|
+
!safeExistsSync(modulePom)
|
|
243
|
+
) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (visited.has(modulePom)) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
pomFiles.add(modulePom);
|
|
250
|
+
queue.push(modulePom);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return pomFiles;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* File name stem for the trees of one recursive dependency:tree run. Maven
|
|
258
|
+
* expands the project expressions for each reactor module, so every module
|
|
259
|
+
* writes its own file; a fixed name would hold only the last module's tree.
|
|
260
|
+
*/
|
|
261
|
+
export const MAVEN_MODULE_TREE_STEM =
|
|
262
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: Maven expands these project expressions itself
|
|
263
|
+
"${project.groupId}-${project.artifactId}";
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* The groupId-artifactId key a module's tree file is named by.
|
|
267
|
+
*
|
|
268
|
+
* @param {string} pomFile Path of the module pom.
|
|
269
|
+
* @returns {string|undefined} The key, or undefined when the pom cannot be read.
|
|
270
|
+
*/
|
|
271
|
+
function moduleTreeKey(pomFile) {
|
|
272
|
+
try {
|
|
273
|
+
const { groupId, artifactId } = parsePom(pomFile)?.properties || {};
|
|
274
|
+
return groupId && artifactId ? `${groupId}-${artifactId}` : undefined;
|
|
275
|
+
} catch (_err) {
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Read the trees one dependency:tree run wrote, one file per reactor module
|
|
282
|
+
* (see MAVEN_MODULE_TREE_STEM), and tell which of the reactor's pom files
|
|
283
|
+
* they cover. The pom the run started from comes first, then its modules in
|
|
284
|
+
* reactor order. A module pom counts as covered only when its own tree is
|
|
285
|
+
* among the files, so a module the run left out still runs on its own.
|
|
286
|
+
*
|
|
287
|
+
* @param {string} treeDir Directory the run wrote its trees into.
|
|
288
|
+
* @param {string} rootPom The pom file the run started from.
|
|
289
|
+
* @returns {{trees: Array<{pomFile: string, text: string}>, covered: Set<string>}}
|
|
290
|
+
*/
|
|
291
|
+
export function readMavenModuleTrees(treeDir, rootPom) {
|
|
292
|
+
const trees = [];
|
|
293
|
+
const covered = new Set();
|
|
294
|
+
let names;
|
|
295
|
+
try {
|
|
296
|
+
names = readdirSync(treeDir).sort();
|
|
297
|
+
} catch (_err) {
|
|
298
|
+
return { trees, covered };
|
|
299
|
+
}
|
|
300
|
+
const byKey = new Map();
|
|
301
|
+
for (const name of names) {
|
|
302
|
+
const stem = name.replace(/\.(json|txt)$/, "");
|
|
303
|
+
if (stem !== name && !byKey.has(stem)) {
|
|
304
|
+
byKey.set(stem, name);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
const take = (key, pomFile) => {
|
|
308
|
+
const name = byKey.get(key);
|
|
309
|
+
if (!name) {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
byKey.delete(key);
|
|
313
|
+
trees.push({
|
|
314
|
+
pomFile,
|
|
315
|
+
text: readFileSync(join(treeDir, name), { encoding: "utf-8" }),
|
|
316
|
+
});
|
|
317
|
+
return true;
|
|
318
|
+
};
|
|
319
|
+
const rootKey = moduleTreeKey(rootPom);
|
|
320
|
+
if (rootKey) {
|
|
321
|
+
take(rootKey, rootPom);
|
|
322
|
+
}
|
|
323
|
+
for (const modulePom of resolveReactorPomFiles(rootPom)) {
|
|
324
|
+
const key = moduleTreeKey(modulePom);
|
|
325
|
+
if (key && take(key, modulePom)) {
|
|
326
|
+
covered.add(modulePom);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// Trees no pom of the reactor names, such as the single file of a Maven
|
|
330
|
+
// that did not expand the expressions, are kept under the root pom.
|
|
331
|
+
for (const key of [...byKey.keys()]) {
|
|
332
|
+
take(key, rootPom);
|
|
333
|
+
}
|
|
334
|
+
return { trees, covered };
|
|
335
|
+
}
|
|
336
|
+
|
|
176
337
|
function mapMavenScope(componentScope, isOptional = false) {
|
|
177
338
|
if (isOptional || componentScope === "test") {
|
|
178
339
|
return "optional";
|
|
@@ -471,10 +632,16 @@ export function parseMavenTree(rawOutput, pomFile) {
|
|
|
471
632
|
/**
|
|
472
633
|
* Parse mill dependencies from file
|
|
473
634
|
*
|
|
635
|
+
* Scala artifacts are emitted in the sbt purl form: the Scala binary suffix
|
|
636
|
+
* is stripped from the artifact name and the version it carried is recorded
|
|
637
|
+
* in the cdx:scala:compilerVersion property, so one library keeps a single
|
|
638
|
+
* purl whichever build tool reported it.
|
|
639
|
+
*
|
|
474
640
|
* @param {string} module name of the module
|
|
475
641
|
* @param {map} dependencies the parsed dependencies
|
|
476
642
|
* @param {map} relations a map containing all relations
|
|
477
643
|
* @param {string} millRootPath root of the project
|
|
644
|
+
* @param {string} logFileName name of the tree log the module wrote
|
|
478
645
|
*
|
|
479
646
|
* @returns the bom-ref of the module
|
|
480
647
|
*/
|
|
@@ -483,6 +650,7 @@ export function parseMillDependency(
|
|
|
483
650
|
dependencies,
|
|
484
651
|
relations,
|
|
485
652
|
millRootPath,
|
|
653
|
+
logFileName = "ivyDepsTree.log",
|
|
486
654
|
) {
|
|
487
655
|
const treeRegex = /^(?<treeIndentation>(?:[?├│└─ ]{3})+)(?<dependency>.*)/m;
|
|
488
656
|
const ESC = "\\x1B";
|
|
@@ -522,12 +690,7 @@ export function parseMillDependency(
|
|
|
522
690
|
// Now put the versions we removed above back into the path and replace the brackets at the same time
|
|
523
691
|
moduleFilePath = moduleFilePath.replace("[]", `/${versionNumber}/`);
|
|
524
692
|
}
|
|
525
|
-
moduleFilePath = resolve(
|
|
526
|
-
millRootPath,
|
|
527
|
-
"out",
|
|
528
|
-
moduleFilePath,
|
|
529
|
-
"ivyDepsTree.log",
|
|
530
|
-
);
|
|
693
|
+
moduleFilePath = resolve(millRootPath, "out", moduleFilePath, logFileName);
|
|
531
694
|
moduleComponent.properties = [
|
|
532
695
|
{
|
|
533
696
|
name: "internal:SrcFile",
|
|
@@ -547,7 +710,27 @@ export function parseMillDependency(
|
|
|
547
710
|
],
|
|
548
711
|
},
|
|
549
712
|
};
|
|
550
|
-
|
|
713
|
+
let dependencyTreeLog;
|
|
714
|
+
try {
|
|
715
|
+
dependencyTreeLog = readFileSync(moduleFilePath, "utf-8");
|
|
716
|
+
} catch (_err) {
|
|
717
|
+
// A cross-published module writes its log under the dotted version
|
|
718
|
+
// directory (0.23.38) while the resolve output prints it with
|
|
719
|
+
// underscores (0_23_38)
|
|
720
|
+
try {
|
|
721
|
+
dependencyTreeLog = readFileSync(
|
|
722
|
+
moduleFilePath.replace(/(\d+)_(\d+)_(\d+)/, "$1.$2.$3"),
|
|
723
|
+
"utf-8",
|
|
724
|
+
);
|
|
725
|
+
} catch (_err2) {
|
|
726
|
+
if (DEBUG_MODE) {
|
|
727
|
+
console.log(
|
|
728
|
+
`No Mill dependency tree log was written for the module ${module}.`,
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
return moduleComponent["bom-ref"];
|
|
732
|
+
}
|
|
733
|
+
}
|
|
551
734
|
const dependencyTreeLines = dependencyTreeLog
|
|
552
735
|
.trim()
|
|
553
736
|
.split("\n")
|
|
@@ -568,11 +751,20 @@ export function parseMillDependency(
|
|
|
568
751
|
[group, name, version] = match.groups.dependency.split(":");
|
|
569
752
|
version = versionRegex.exec(version).groups.version;
|
|
570
753
|
}
|
|
754
|
+
const scalaInfo = parseScalaArtifact(name);
|
|
571
755
|
const component = completeComponent({
|
|
572
756
|
group,
|
|
573
|
-
name,
|
|
757
|
+
name: scalaInfo.purlName,
|
|
574
758
|
version,
|
|
575
759
|
});
|
|
760
|
+
if (scalaInfo.binaryVersion) {
|
|
761
|
+
component.properties = [
|
|
762
|
+
{
|
|
763
|
+
name: "cdx:scala:compilerVersion",
|
|
764
|
+
value: scalaInfo.binaryVersion,
|
|
765
|
+
},
|
|
766
|
+
];
|
|
767
|
+
}
|
|
576
768
|
if (!dependencies.has(component["bom-ref"])) {
|
|
577
769
|
dependencies.set(component["bom-ref"], component);
|
|
578
770
|
relations.set(component["bom-ref"], []);
|
|
@@ -587,7 +779,7 @@ export function parseMillDependency(
|
|
|
587
779
|
return moduleComponent["bom-ref"];
|
|
588
780
|
}
|
|
589
781
|
|
|
590
|
-
function completeComponent(component) {
|
|
782
|
+
export function completeComponent(component) {
|
|
591
783
|
component["type"] = component.group ? "library" : "application";
|
|
592
784
|
try {
|
|
593
785
|
const purl = build({
|