@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
|
@@ -18,7 +18,7 @@ import { recordDegradation } from "../core/buildLedger.js";
|
|
|
18
18
|
import { shouldFetchPackageMetadata } from "../core/env.js";
|
|
19
19
|
import { safeExistsSync } from "../core/fs.js";
|
|
20
20
|
import { analyzeSuspiciousJsFile } from "../inventory/analyzer.js";
|
|
21
|
-
import {
|
|
21
|
+
import { npmPurl, parsePurlLoose } from "../inventory/purl.js";
|
|
22
22
|
import Arborist from "../third-party/arborist/lib/index.js";
|
|
23
23
|
import { getNpmMetadata } from "./ecosystems.js";
|
|
24
24
|
import {
|
|
@@ -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,22 +929,36 @@ 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
|
|
916
947
|
// no version rather than an empty one.
|
|
917
|
-
purlString =
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
948
|
+
purlString = (
|
|
949
|
+
projectGroup
|
|
950
|
+
? build({
|
|
951
|
+
type: "npm",
|
|
952
|
+
namespace: projectGroup,
|
|
953
|
+
name: projectName,
|
|
954
|
+
version: projectVersion || null,
|
|
955
|
+
})
|
|
956
|
+
: npmPurl(projectName, projectVersion)
|
|
957
|
+
).replace(/%2F/g, "/");
|
|
922
958
|
pkg = {
|
|
923
959
|
author: authorString,
|
|
924
960
|
group: options.projectGroup || "",
|
|
925
|
-
name:
|
|
926
|
-
"project-name" in options ? options.projectName : node.packageName,
|
|
961
|
+
name: projectName,
|
|
927
962
|
version: options.projectVersion || node.version,
|
|
928
963
|
type: "application",
|
|
929
964
|
purl: purlString,
|
|
@@ -959,13 +994,19 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
959
994
|
});
|
|
960
995
|
}
|
|
961
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 || "");
|
|
962
1003
|
let namespace = "";
|
|
963
|
-
let name =
|
|
964
|
-
if (
|
|
965
|
-
const slashIndex =
|
|
1004
|
+
let name = packageName;
|
|
1005
|
+
if (packageName.startsWith("@")) {
|
|
1006
|
+
const slashIndex = packageName.indexOf("/");
|
|
966
1007
|
if (slashIndex > 0) {
|
|
967
|
-
namespace =
|
|
968
|
-
name =
|
|
1008
|
+
namespace = packageName.substring(0, slashIndex);
|
|
1009
|
+
name = packageName.substring(slashIndex + 1);
|
|
969
1010
|
}
|
|
970
1011
|
}
|
|
971
1012
|
let qualifiers = null;
|
|
@@ -1078,9 +1119,17 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1078
1119
|
});
|
|
1079
1120
|
}
|
|
1080
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).
|
|
1081
1126
|
pkg.properties.push({
|
|
1082
1127
|
name: "cdx:npm:binPaths",
|
|
1083
|
-
value: node.binPaths
|
|
1128
|
+
value: node.binPaths
|
|
1129
|
+
.map((binPath) =>
|
|
1130
|
+
relative(srcFilePath, binPath).split(_sep).join("/"),
|
|
1131
|
+
)
|
|
1132
|
+
.join(", "),
|
|
1084
1133
|
});
|
|
1085
1134
|
}
|
|
1086
1135
|
if (nodePackage?.bin) {
|
|
@@ -1149,9 +1198,14 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1149
1198
|
try {
|
|
1150
1199
|
const onDiskPkg =
|
|
1151
1200
|
diskPkg || JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
1152
|
-
|
|
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
|
+
) {
|
|
1153
1207
|
console.warn(
|
|
1154
|
-
`\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`,
|
|
1155
1209
|
);
|
|
1156
1210
|
if (onDiskPkg.name) {
|
|
1157
1211
|
pkg.properties.push({
|
|
@@ -1160,9 +1214,12 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1160
1214
|
});
|
|
1161
1215
|
}
|
|
1162
1216
|
}
|
|
1163
|
-
if (
|
|
1217
|
+
if (
|
|
1218
|
+
(onDiskPkg.version || node.version) &&
|
|
1219
|
+
onDiskPkg.version !== node.version
|
|
1220
|
+
) {
|
|
1164
1221
|
console.warn(
|
|
1165
|
-
`\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`,
|
|
1166
1223
|
);
|
|
1167
1224
|
if (onDiskPkg.version) {
|
|
1168
1225
|
pkg.properties.push({
|
|
@@ -1171,6 +1228,17 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1171
1228
|
});
|
|
1172
1229
|
}
|
|
1173
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
|
+
}
|
|
1174
1242
|
} catch (_err) {
|
|
1175
1243
|
// ignore
|
|
1176
1244
|
}
|
|
@@ -1226,9 +1294,11 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1226
1294
|
pkg.description = nodePackage.description;
|
|
1227
1295
|
}
|
|
1228
1296
|
}
|
|
1229
|
-
|
|
1297
|
+
const npmLicense =
|
|
1298
|
+
resolveNpmLicense(nodePackage) || installedManifestLicense;
|
|
1299
|
+
if (npmLicense) {
|
|
1230
1300
|
// License will be overridden if shouldFetchLicense() is enabled
|
|
1231
|
-
pkg.license =
|
|
1301
|
+
pkg.license = npmLicense;
|
|
1232
1302
|
}
|
|
1233
1303
|
const deprecatedMessage = nodePackage?.deprecated;
|
|
1234
1304
|
if (deprecatedMessage) {
|
|
@@ -1602,7 +1672,7 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
1602
1672
|
`About to fetch npm registry metadata for ${pkgList.length} packages in parsePkgLock`,
|
|
1603
1673
|
);
|
|
1604
1674
|
}
|
|
1605
|
-
pkgList = await getNpmMetadata(pkgList);
|
|
1675
|
+
pkgList = await getNpmMetadata(pkgList, undefined, { npmrcConfig });
|
|
1606
1676
|
return { pkgList, dependenciesList };
|
|
1607
1677
|
}
|
|
1608
1678
|
return {
|
|
@@ -1778,17 +1848,15 @@ function _resolveYarnDependencyBomRef(
|
|
|
1778
1848
|
packageNameToUse,
|
|
1779
1849
|
);
|
|
1780
1850
|
if (matchingWorkspace) {
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1851
|
+
// The workspace reference may be an escaped purl, so its version is read
|
|
1852
|
+
// through the purl parser rather than cut out of the string.
|
|
1853
|
+
resolvedVersion =
|
|
1854
|
+
parsePurlLoose(matchingWorkspace)?.version || resolvedVersion;
|
|
1785
1855
|
}
|
|
1786
1856
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
}
|
|
1791
|
-
return decodeURIComponent(Purl.parse(purlPart).toString());
|
|
1857
|
+
return decodeURIComponent(
|
|
1858
|
+
npmPurl(packageNameToUse, resolvedVersion?.length ? resolvedVersion : null),
|
|
1859
|
+
);
|
|
1792
1860
|
}
|
|
1793
1861
|
|
|
1794
1862
|
function _collectYarnRootDependencyRefs(
|
|
@@ -1919,7 +1987,7 @@ function _markYarnDependencyScopeClosures(
|
|
|
1919
1987
|
* @param {Object} parentComponent parent component
|
|
1920
1988
|
* @param {Array[String]} workspacePackages Workspace packages
|
|
1921
1989
|
* @param {Object} workspaceSrcFiles Workspace package.json files
|
|
1922
|
-
* @param {Object}
|
|
1990
|
+
* @param {Object} workspaceDirectDeps Declared dependencies (name to range) of each workspace package
|
|
1923
1991
|
* @param {Object} depsWorkspaceRefs Workspace references for each dependency
|
|
1924
1992
|
*/
|
|
1925
1993
|
export async function parseYarnLock(
|
|
@@ -1927,12 +1995,14 @@ export async function parseYarnLock(
|
|
|
1927
1995
|
parentComponent = null,
|
|
1928
1996
|
workspacePackages = [],
|
|
1929
1997
|
workspaceSrcFiles = {},
|
|
1930
|
-
|
|
1998
|
+
workspaceDirectDeps = {},
|
|
1931
1999
|
depsWorkspaceRefs = {},
|
|
1932
2000
|
) {
|
|
1933
2001
|
let pkgList = [];
|
|
1934
2002
|
const dependenciesList = [];
|
|
1935
2003
|
const depKeys = {};
|
|
2004
|
+
// The lock keys and the resolved version required to solve the dependency tree
|
|
2005
|
+
let identMap = {};
|
|
1936
2006
|
let yarnRootRefs = _createYarnRootDependencyRefs();
|
|
1937
2007
|
const yarnOptionalDependencyRefs = new Set();
|
|
1938
2008
|
const npmrcConfig = loadNpmrcConfig(dirname(yarnLockFile));
|
|
@@ -1951,8 +2021,7 @@ export async function parseYarnLock(
|
|
|
1951
2021
|
const pkgAddedMap = {};
|
|
1952
2022
|
// Map to track workspace package PURL replacements from 0.0.0-use.local to actual versions
|
|
1953
2023
|
const workspacePurlMap = {};
|
|
1954
|
-
|
|
1955
|
-
const identMap = yarnLockToIdentMap(lockData);
|
|
2024
|
+
identMap = yarnLockToIdentMap(lockData);
|
|
1956
2025
|
yarnRootRefs = _collectYarnRootDependencyRefs(
|
|
1957
2026
|
yarnLockFile,
|
|
1958
2027
|
identMap,
|
|
@@ -2020,8 +2089,8 @@ export async function parseYarnLock(
|
|
|
2020
2089
|
const actualWorkspacePurl = workspacePackages.find(
|
|
2021
2090
|
(wp) =>
|
|
2022
2091
|
wp.startsWith(expectedPurlStart) ||
|
|
2023
|
-
wp.
|
|
2024
|
-
|
|
2092
|
+
wp.startsWith(
|
|
2093
|
+
`${npmPurl(group ? `${group}/${name}` : name)}@`,
|
|
2025
2094
|
),
|
|
2026
2095
|
);
|
|
2027
2096
|
// Also check if this package already exists in pkgList with a real version
|
|
@@ -2286,23 +2355,21 @@ export async function parseYarnLock(
|
|
|
2286
2355
|
if (DEBUG_MODE) {
|
|
2287
2356
|
console.log(`Processing workspace package: "${workspacePkg}"`);
|
|
2288
2357
|
}
|
|
2289
|
-
|
|
2290
|
-
//
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
) {
|
|
2295
|
-
|
|
2296
|
-
const lastAtIndex = workspacePkg.lastIndexOf("@");
|
|
2297
|
-
const purlWithoutVersion = workspacePkg.substring(0, lastAtIndex);
|
|
2298
|
-
const version = workspacePkg.substring(lastAtIndex + 1);
|
|
2299
|
-
// Parse the PURL without version first, then set the version.
|
|
2300
|
-
purlObj = Purl.parse(purlWithoutVersion);
|
|
2301
|
-
purlObj.version = version;
|
|
2302
|
-
} else {
|
|
2303
|
-
// Parse the PURL as-is (no version or simple package)
|
|
2304
|
-
purlObj = Purl.parse(workspacePkg);
|
|
2358
|
+
// Workspace references arrive both escaped (built by cdx-purl) and in
|
|
2359
|
+
// the decoded bom-ref form, so they are split structurally and
|
|
2360
|
+
// rebuilt. Copying the version text across forms is what turned
|
|
2361
|
+
// `3.0.0+ws` into `3.0.0%252Bws`.
|
|
2362
|
+
const workspaceParts = parsePurlLoose(workspacePkg);
|
|
2363
|
+
if (!workspaceParts) {
|
|
2364
|
+
continue;
|
|
2305
2365
|
}
|
|
2366
|
+
const purlObj = new Purl({
|
|
2367
|
+
type: "npm",
|
|
2368
|
+
namespace: workspaceParts.namespace,
|
|
2369
|
+
name: workspaceParts.name,
|
|
2370
|
+
version: workspaceParts.version,
|
|
2371
|
+
subpath: workspaceParts.subpath,
|
|
2372
|
+
});
|
|
2306
2373
|
|
|
2307
2374
|
// Create the workspace component using the properly parsed PURL
|
|
2308
2375
|
const workspaceComponent = {
|
|
@@ -2405,6 +2472,41 @@ export async function parseYarnLock(
|
|
|
2405
2472
|
}
|
|
2406
2473
|
}
|
|
2407
2474
|
}
|
|
2475
|
+
// A yarn v1 lock file has no entries for workspace packages, so a member
|
|
2476
|
+
// would otherwise have no dependency entry and nothing would reach it.
|
|
2477
|
+
// Each member gets one built from the dependencies its own package.json
|
|
2478
|
+
// declares; the root's entry, built from every dependency entry, then
|
|
2479
|
+
// includes the member too. A lock file that already recorded the member
|
|
2480
|
+
// (yarn berry) keeps the entry it produced.
|
|
2481
|
+
const recordedRefs = new Set(dependenciesList.map((d) => d.ref));
|
|
2482
|
+
for (const workspacePkg of workspacePackages) {
|
|
2483
|
+
const workspaceRef = decodeURIComponent(workspacePkg);
|
|
2484
|
+
if (
|
|
2485
|
+
recordedRefs.has(workspaceRef) ||
|
|
2486
|
+
!pkgList.some((pkg) => pkg["bom-ref"] === workspaceRef)
|
|
2487
|
+
) {
|
|
2488
|
+
continue;
|
|
2489
|
+
}
|
|
2490
|
+
const dependsOn = new Set();
|
|
2491
|
+
for (const [depName, depRange] of Object.entries(
|
|
2492
|
+
workspaceDirectDeps?.[workspacePkg] || {},
|
|
2493
|
+
)) {
|
|
2494
|
+
const depRef = _resolveYarnDependencyBomRef(
|
|
2495
|
+
depName,
|
|
2496
|
+
String(depRange),
|
|
2497
|
+
identMap,
|
|
2498
|
+
workspacePackages,
|
|
2499
|
+
);
|
|
2500
|
+
if (depRef && depRef !== workspaceRef) {
|
|
2501
|
+
dependsOn.add(depRef);
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
dependenciesList.push({
|
|
2505
|
+
ref: workspaceRef,
|
|
2506
|
+
dependsOn: [...dependsOn].sort(),
|
|
2507
|
+
});
|
|
2508
|
+
recordedRefs.add(workspaceRef);
|
|
2509
|
+
}
|
|
2408
2510
|
}
|
|
2409
2511
|
|
|
2410
2512
|
_markYarnDependencyScopeClosures(
|
|
@@ -2420,7 +2522,7 @@ export async function parseYarnLock(
|
|
|
2420
2522
|
`About to fetch npm registry metadata for ${pkgList.length} packages in parseYarnLock`,
|
|
2421
2523
|
);
|
|
2422
2524
|
}
|
|
2423
|
-
pkgList = await getNpmMetadata(pkgList);
|
|
2525
|
+
pkgList = await getNpmMetadata(pkgList, undefined, { npmrcConfig });
|
|
2424
2526
|
return {
|
|
2425
2527
|
pkgList,
|
|
2426
2528
|
dependenciesList,
|
|
@@ -2439,6 +2541,7 @@ export async function parseYarnLock(
|
|
|
2439
2541
|
*/
|
|
2440
2542
|
export async function parseNodeShrinkwrap(swFile) {
|
|
2441
2543
|
const pkgList = [];
|
|
2544
|
+
const npmrcConfig = loadNpmrcConfig(dirname(swFile));
|
|
2442
2545
|
if (safeExistsSync(swFile)) {
|
|
2443
2546
|
const lockData = JSON.parse(readFileSync(swFile, "utf8"));
|
|
2444
2547
|
const pkgKeys = Object.keys(lockData);
|
|
@@ -2497,7 +2600,7 @@ export async function parseNodeShrinkwrap(swFile) {
|
|
|
2497
2600
|
`About to fetch npm registry metadata for ${pkgList.length} packages in parseNodeShrinkwrap`,
|
|
2498
2601
|
);
|
|
2499
2602
|
}
|
|
2500
|
-
return await getNpmMetadata(pkgList);
|
|
2603
|
+
return await getNpmMetadata(pkgList, undefined, { npmrcConfig });
|
|
2501
2604
|
}
|
|
2502
2605
|
return pkgList;
|
|
2503
2606
|
}
|
|
@@ -2646,7 +2749,10 @@ export function stripPnpmPeerSuffix(version) {
|
|
|
2646
2749
|
* {@link stripPnpmPeerSuffix}.
|
|
2647
2750
|
*
|
|
2648
2751
|
* @param {string|object} depPkg Dependency version string or package object.
|
|
2649
|
-
* @param {string} relativePath Base path for resolving link/file references
|
|
2752
|
+
* @param {string} relativePath Base path for resolving link/file references:
|
|
2753
|
+
* the directory of the importer that declares the dependency. Without it the
|
|
2754
|
+
* path is tried against the working directory, which only works when cdxgen
|
|
2755
|
+
* runs from the lock file's directory.
|
|
2650
2756
|
* @returns {Promise<string|undefined>} The resolved published version.
|
|
2651
2757
|
*/
|
|
2652
2758
|
export async function getVersionNumPnpm(depPkg, relativePath) {
|
|
@@ -2662,13 +2768,13 @@ export async function getVersionNumPnpm(depPkg, relativePath) {
|
|
|
2662
2768
|
: join(version.replaceAll("../", "packages/"), "package.json");
|
|
2663
2769
|
if (safeExistsSync(relativePkgJson)) {
|
|
2664
2770
|
const importedComponentObj = await parsePkgJson(relativePkgJson, true);
|
|
2665
|
-
version = importedComponentObj[0]
|
|
2771
|
+
version = importedComponentObj[0]?.version;
|
|
2666
2772
|
} else if (safeExistsSync(join(version, "package.json"))) {
|
|
2667
2773
|
const importedComponentObj = await parsePkgJson(
|
|
2668
2774
|
join(version, "package.json"),
|
|
2669
2775
|
true,
|
|
2670
2776
|
);
|
|
2671
|
-
version = importedComponentObj[0]
|
|
2777
|
+
version = importedComponentObj[0]?.version;
|
|
2672
2778
|
} else if (
|
|
2673
2779
|
safeExistsSync(join(version.replaceAll("../", ""), "package.json"))
|
|
2674
2780
|
) {
|
|
@@ -2676,7 +2782,7 @@ export async function getVersionNumPnpm(depPkg, relativePath) {
|
|
|
2676
2782
|
join(version.replaceAll("../", ""), "package.json"),
|
|
2677
2783
|
true,
|
|
2678
2784
|
);
|
|
2679
|
-
version = importedComponentObj[0]
|
|
2785
|
+
version = importedComponentObj[0]?.version;
|
|
2680
2786
|
}
|
|
2681
2787
|
} else {
|
|
2682
2788
|
// version: 3.0.1(ajv@8.14.0) or, under lockfile 5, 3.0.1_ajv@8.14.0
|
|
@@ -2685,6 +2791,25 @@ export async function getVersionNumPnpm(depPkg, relativePath) {
|
|
|
2685
2791
|
return version;
|
|
2686
2792
|
}
|
|
2687
2793
|
|
|
2794
|
+
/**
|
|
2795
|
+
* Split the package name of a pnpm `file:` lock key into scope and name.
|
|
2796
|
+
*
|
|
2797
|
+
* @param {string} fullName Package name as written before `@file:`, eg `@scope/pkg`
|
|
2798
|
+
* @returns {{group: string, name: string}} Scope (with its `@`) and bare name
|
|
2799
|
+
*/
|
|
2800
|
+
function splitPnpmFilePackageName(fullName) {
|
|
2801
|
+
if (fullName.startsWith("@")) {
|
|
2802
|
+
const slash = fullName.indexOf("/");
|
|
2803
|
+
if (slash > 0) {
|
|
2804
|
+
return {
|
|
2805
|
+
group: fullName.slice(0, slash),
|
|
2806
|
+
name: fullName.slice(slash + 1),
|
|
2807
|
+
};
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
return { group: "", name: fullName };
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2688
2813
|
/**
|
|
2689
2814
|
* Resolve a pnpm dependency to its PURL string.
|
|
2690
2815
|
*
|
|
@@ -2723,11 +2848,16 @@ export async function getPnpmDepPurl(
|
|
|
2723
2848
|
}
|
|
2724
2849
|
gitPkgRefs[versionObj.version] = { group, name, version };
|
|
2725
2850
|
} else {
|
|
2851
|
+
const rawSpec =
|
|
2852
|
+
typeof versionObj?.version === "string" ? versionObj.version : "";
|
|
2726
2853
|
version = await getVersionNumPnpm(depPkg, relativePath);
|
|
2727
2854
|
const gitEntry =
|
|
2728
2855
|
gitPkgRefs[packageName] ||
|
|
2729
2856
|
gitPkgRefs[version] ||
|
|
2730
|
-
gitPkgRefs[normalizePnpmLockKey(`${packageName}@${version}`)]
|
|
2857
|
+
gitPkgRefs[normalizePnpmLockKey(`${packageName}@${version}`)] ||
|
|
2858
|
+
(rawSpec.startsWith("file:")
|
|
2859
|
+
? gitPkgRefs[normalizePnpmLockKey(`${packageName}@${rawSpec}`)]
|
|
2860
|
+
: undefined);
|
|
2731
2861
|
if (gitEntry) {
|
|
2732
2862
|
group = gitEntry.group;
|
|
2733
2863
|
name = gitEntry.name;
|
|
@@ -2980,7 +3110,8 @@ export async function pnpmMetadata(pkgList, lockFilePath) {
|
|
|
2980
3110
|
// Silently ignore parsing errors for individual packages
|
|
2981
3111
|
if (DEBUG_MODE) {
|
|
2982
3112
|
console.log(
|
|
2983
|
-
|
|
3113
|
+
"Failed to parse package.json at %s:",
|
|
3114
|
+
packageJsonPath,
|
|
2984
3115
|
error.message,
|
|
2985
3116
|
);
|
|
2986
3117
|
}
|
|
@@ -3148,6 +3279,33 @@ export async function parsePnpmLock(
|
|
|
3148
3279
|
npmrcConfig,
|
|
3149
3280
|
),
|
|
3150
3281
|
);
|
|
3282
|
+
// A `file:` package is keyed by its path (`localdep@file:localdep.tgz`) and
|
|
3283
|
+
// pnpm copies the manifest version into its `packages` entry. Registering
|
|
3284
|
+
// it lets an importer that names the path resolve to the same ref the
|
|
3285
|
+
// package loop below builds, instead of a version made from the path.
|
|
3286
|
+
if (lockfileVersion >= 9) {
|
|
3287
|
+
for (const [lockKey, pkgEntry] of Object.entries(
|
|
3288
|
+
yamlObj.packages || {},
|
|
3289
|
+
)) {
|
|
3290
|
+
const fileAt = lockKey.indexOf("@file:", 1);
|
|
3291
|
+
if (fileAt < 1 || !pkgEntry?.version) {
|
|
3292
|
+
continue;
|
|
3293
|
+
}
|
|
3294
|
+
const normalizedKey = normalizePnpmLockKey(lockKey);
|
|
3295
|
+
if (gitPkgRefs[normalizedKey]) {
|
|
3296
|
+
continue;
|
|
3297
|
+
}
|
|
3298
|
+
const { group, name } = splitPnpmFilePackageName(
|
|
3299
|
+
lockKey.slice(0, fileAt),
|
|
3300
|
+
);
|
|
3301
|
+
gitPkgRefs[normalizedKey] = {
|
|
3302
|
+
group,
|
|
3303
|
+
name,
|
|
3304
|
+
version: String(pkgEntry.version),
|
|
3305
|
+
vcsUrl: lockKey.slice(fileAt + 1),
|
|
3306
|
+
};
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3151
3309
|
// This logic matches the pnpm list command to include only direct dependencies
|
|
3152
3310
|
if (ppurl !== "" && yamlObj?.importers) {
|
|
3153
3311
|
// In lock file version 6, direct dependencies is under importers
|
|
@@ -3184,7 +3342,7 @@ export async function parsePnpmLock(
|
|
|
3184
3342
|
rootDevDeps[rdk],
|
|
3185
3343
|
rdk,
|
|
3186
3344
|
gitPkgRefs,
|
|
3187
|
-
|
|
3345
|
+
pnpmLockDir,
|
|
3188
3346
|
githubServerHost,
|
|
3189
3347
|
npmrcConfig,
|
|
3190
3348
|
);
|
|
@@ -3206,7 +3364,7 @@ export async function parsePnpmLock(
|
|
|
3206
3364
|
rootOptionalDeps[rdk] || rootPeerDeps[rdk],
|
|
3207
3365
|
rdk,
|
|
3208
3366
|
gitPkgRefs,
|
|
3209
|
-
|
|
3367
|
+
pnpmLockDir,
|
|
3210
3368
|
githubServerHost,
|
|
3211
3369
|
npmrcConfig,
|
|
3212
3370
|
);
|
|
@@ -3229,7 +3387,7 @@ export async function parsePnpmLock(
|
|
|
3229
3387
|
rootDirectDeps[dk],
|
|
3230
3388
|
dk,
|
|
3231
3389
|
gitPkgRefs,
|
|
3232
|
-
|
|
3390
|
+
pnpmLockDir,
|
|
3233
3391
|
githubServerHost,
|
|
3234
3392
|
npmrcConfig,
|
|
3235
3393
|
);
|
|
@@ -3340,7 +3498,7 @@ export async function parsePnpmLock(
|
|
|
3340
3498
|
versionObj,
|
|
3341
3499
|
cdk,
|
|
3342
3500
|
gitPkgRefs,
|
|
3343
|
-
importedComponentName,
|
|
3501
|
+
join(pnpmLockDir, importedComponentName),
|
|
3344
3502
|
githubServerHost,
|
|
3345
3503
|
npmrcConfig,
|
|
3346
3504
|
);
|
|
@@ -3357,7 +3515,10 @@ export async function parsePnpmLock(
|
|
|
3357
3515
|
}
|
|
3358
3516
|
}
|
|
3359
3517
|
for (const cdk of Object.keys(componentDevDeps)) {
|
|
3360
|
-
const version = await getVersionNumPnpm(
|
|
3518
|
+
const version = await getVersionNumPnpm(
|
|
3519
|
+
componentDevDeps[cdk],
|
|
3520
|
+
join(pnpmLockDir, importedComponentName),
|
|
3521
|
+
);
|
|
3361
3522
|
const dpurl = build({
|
|
3362
3523
|
type: "npm",
|
|
3363
3524
|
namespace: "" || null,
|
|
@@ -3375,6 +3536,7 @@ export async function parsePnpmLock(
|
|
|
3375
3536
|
})) {
|
|
3376
3537
|
const version = await getVersionNumPnpm(
|
|
3377
3538
|
componentOptionalDeps[cdk] || componentPeerDeps[cdk],
|
|
3539
|
+
join(pnpmLockDir, importedComponentName),
|
|
3378
3540
|
);
|
|
3379
3541
|
const dpurl = build({
|
|
3380
3542
|
type: "npm",
|
|
@@ -3399,6 +3561,11 @@ export async function parsePnpmLock(
|
|
|
3399
3561
|
// snapshots is a new key under lockfile version 9
|
|
3400
3562
|
const snapshots = yamlObj.snapshots || {};
|
|
3401
3563
|
const pkgKeys = { ...Object.keys(packages), ...Object.keys(snapshots) };
|
|
3564
|
+
// A lock entry named `__proto__` is not a real package: emitting it as a
|
|
3565
|
+
// component produces SBOM data that breaks naive JSON consumers, and the
|
|
3566
|
+
// name can never come from the npm registry. Legitimate names such as
|
|
3567
|
+
// `constructor` or `prototype` are unaffected.
|
|
3568
|
+
const protoLockKey = /(^|\/)__proto__(@|$)/;
|
|
3402
3569
|
for (const k in pkgKeys) {
|
|
3403
3570
|
// Eg: @babel/code-frame/7.10.1
|
|
3404
3571
|
// In lockfileVersion 6, /@babel/code-frame@7.18.6
|
|
@@ -3407,6 +3574,9 @@ export async function parsePnpmLock(
|
|
|
3407
3574
|
if (lockfileVersion >= 6 && fullName.includes("(")) {
|
|
3408
3575
|
fullName = fullName.split("(")[0];
|
|
3409
3576
|
}
|
|
3577
|
+
if (protoLockKey.test(pkgKeys[k]) || protoLockKey.test(fullName)) {
|
|
3578
|
+
continue;
|
|
3579
|
+
}
|
|
3410
3580
|
const parts = fullName.split("/");
|
|
3411
3581
|
const packageNode =
|
|
3412
3582
|
packages[pkgKeys[k]] ||
|
|
@@ -3465,9 +3635,17 @@ export async function parsePnpmLock(
|
|
|
3465
3635
|
}
|
|
3466
3636
|
let opurlString;
|
|
3467
3637
|
if (vers.includes("@")) {
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3638
|
+
// An aliased optional dependency records `name@version`, and the
|
|
3639
|
+
// version may carry semver build metadata that must be escaped.
|
|
3640
|
+
const aliasParts = parsePurlLoose(`pkg:npm/${vers}`);
|
|
3641
|
+
opurlString = aliasParts
|
|
3642
|
+
? npmPurl(
|
|
3643
|
+
aliasParts.namespace
|
|
3644
|
+
? `${aliasParts.namespace}/${aliasParts.name}`
|
|
3645
|
+
: aliasParts.name,
|
|
3646
|
+
aliasParts.version,
|
|
3647
|
+
)
|
|
3648
|
+
: npmPurl(opkgName, vers);
|
|
3471
3649
|
} else {
|
|
3472
3650
|
opurlString = npmPurl(opkgName, vers);
|
|
3473
3651
|
}
|
|
@@ -3536,8 +3714,17 @@ export async function parsePnpmLock(
|
|
|
3536
3714
|
possibleHttpParts[possibleHttpParts.length - 1].startsWith("file")
|
|
3537
3715
|
) {
|
|
3538
3716
|
srcUrl = possibleHttpParts[possibleHttpParts.length - 1];
|
|
3539
|
-
name =
|
|
3540
|
-
|
|
3717
|
+
({ group, name } = splitPnpmFilePackageName(
|
|
3718
|
+
fullName.replace(`@${srcUrl}`, ""),
|
|
3719
|
+
));
|
|
3720
|
+
// The key names the path, not a version. pnpm copies the version
|
|
3721
|
+
// from the package's own manifest into its `packages` entry, and
|
|
3722
|
+
// that may carry semver build metadata (`2.0.0+local`).
|
|
3723
|
+
version = String(
|
|
3724
|
+
packages[pkgKeys[k]]?.version ||
|
|
3725
|
+
packages[fullName]?.version ||
|
|
3726
|
+
"",
|
|
3727
|
+
);
|
|
3541
3728
|
} else {
|
|
3542
3729
|
group = parts.length > 1 ? parts[0] : "";
|
|
3543
3730
|
const tmpA = parts[parts.length - 1].split("@");
|
|
@@ -4004,7 +4191,7 @@ export async function parsePnpmLock(
|
|
|
4004
4191
|
`About to fetch npm registry metadata for ${pkgList.length} packages in parsePnpmLock`,
|
|
4005
4192
|
);
|
|
4006
4193
|
}
|
|
4007
|
-
pkgList = await getNpmMetadata(pkgList);
|
|
4194
|
+
pkgList = await getNpmMetadata(pkgList, undefined, { npmrcConfig });
|
|
4008
4195
|
return {
|
|
4009
4196
|
pkgList,
|
|
4010
4197
|
dependenciesList,
|
|
@@ -4034,7 +4221,7 @@ export async function parseBowerJson(bowerJsonFile) {
|
|
|
4034
4221
|
group: pkgIdentifier.scope || "",
|
|
4035
4222
|
version: pkgData.version || "",
|
|
4036
4223
|
description: pkgData.description || "",
|
|
4037
|
-
license: pkgData
|
|
4224
|
+
license: resolveNpmLicense(pkgData) || "",
|
|
4038
4225
|
properties: [
|
|
4039
4226
|
{
|
|
4040
4227
|
name: "internal:SrcFile",
|