@cdxgen/cdxgen 13.1.0 → 13.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -15
- package/bin/cdxgen.js +243 -122
- package/bin/evinse.js +7 -0
- package/bin/sign.js +88 -14
- package/bin/tracebom.js +64 -4
- package/bin/validate.js +29 -7
- package/bin/verify.js +79 -39
- package/data/crypto-oid.json +88 -12
- package/data/remediations.json +47 -0
- package/data/rules/ai-bom.yaml +78 -0
- package/data/rules/cargo-rust.yaml +132 -0
- package/data/rules/mcp-servers.yaml +122 -0
- package/lib/audit/targets.js +6 -1
- package/lib/cli/bomAssembly.js +117 -15
- package/lib/cli/cliOptions.js +93 -1
- package/lib/cli/index.js +235 -5
- package/lib/cli/jsBom.js +108 -26
- package/lib/cli/jvmBom.js +68 -12
- package/lib/cli/managedBom.js +264 -41
- package/lib/cli/nativeBom.js +923 -15
- package/lib/core/activity.js +120 -2
- package/lib/core/env.js +44 -7
- package/lib/core/fs.js +174 -6
- package/lib/core/metadataProperties.js +97 -0
- package/lib/core/projectConfig.js +31 -4
- package/lib/core/userAgent.js +151 -0
- package/lib/ecosystems/bunutils.js +269 -101
- package/lib/ecosystems/cargoCache.js +364 -0
- package/lib/ecosystems/caxa.js +447 -7
- package/lib/ecosystems/cmakeResolver.js +66 -0
- package/lib/ecosystems/cppEvidence.js +104 -33
- package/lib/ecosystems/ecosystems.js +260 -99
- package/lib/ecosystems/golem.js +11 -1
- package/lib/ecosystems/gradleutils.js +185 -9
- package/lib/ecosystems/jsEvidence.js +19 -20
- package/lib/ecosystems/kosi.js +1263 -0
- package/lib/ecosystems/npmutils.js +110 -9
- package/lib/ecosystems/parsers-crystal.js +179 -0
- package/lib/ecosystems/parsers-dotnet.js +120 -49
- package/lib/ecosystems/parsers-elm.js +816 -0
- package/lib/ecosystems/parsers-gleam.js +1 -1
- package/lib/ecosystems/parsers-go.js +47 -9
- package/lib/ecosystems/parsers-js.js +171 -50
- package/lib/ecosystems/parsers-julia.js +268 -0
- package/lib/ecosystems/parsers-lua.js +218 -0
- package/lib/ecosystems/parsers-misc.js +919 -161
- package/lib/ecosystems/parsers-nim.js +221 -0
- package/lib/ecosystems/parsers-opam.js +180 -0
- package/lib/ecosystems/parsers-perl.js +277 -0
- package/lib/ecosystems/parsers-python.js +27 -15
- package/lib/ecosystems/parsers-r.js +148 -0
- package/lib/ecosystems/parsers-rebar.js +411 -0
- package/lib/ecosystems/parsers-rust.js +954 -33
- package/lib/ecosystems/parsers-spack.js +204 -0
- package/lib/ecosystems/parsers-stack.js +264 -0
- package/lib/ecosystems/parsers-terraform.js +194 -0
- package/lib/ecosystems/rubyutils.js +1426 -166
- package/lib/ecosystems/rusi.js +158 -7
- package/lib/evinser/evinser.js +547 -129
- package/lib/evinser/swiftsem.js +1914 -302
- package/lib/helpers/agenticToolutils.js +925 -0
- package/lib/helpers/bomSigner.js +652 -221
- package/lib/inventory/agentFormulationParser.js +57 -4
- package/lib/inventory/aiCollector.js +504 -10
- package/lib/inventory/aiInventory.js +12 -0
- package/lib/inventory/analyzer.js +488 -30
- package/lib/inventory/astWorker.js +6 -0
- package/lib/inventory/atomUtils.js +568 -31
- package/lib/inventory/auditCategories.js +8 -0
- package/lib/inventory/cbomutils.js +30 -0
- package/lib/inventory/cdxrs.js +110 -14
- package/lib/inventory/communityAiConfigParser.js +215 -2
- package/lib/inventory/depsUtils.js +183 -11
- package/lib/inventory/display.js +4 -5
- package/lib/inventory/dosai.js +627 -13
- package/lib/inventory/dynamic.js +39 -1
- package/lib/inventory/envcontext.js +9 -6
- package/lib/inventory/evidenceUtils.js +26 -5
- package/lib/inventory/fetchBatch.js +190 -19
- package/lib/inventory/fetchRate.js +74 -11
- package/lib/inventory/forgeEnricher.js +3 -2
- package/lib/inventory/jvmToolEnv.js +6 -5
- package/lib/inventory/mcpConfigParser.js +166 -2
- package/lib/inventory/mcpDiscovery.js +11 -0
- package/lib/inventory/mcpServerManifest.js +389 -0
- package/lib/inventory/mcpbBundle.js +419 -0
- package/lib/inventory/plugins.js +3 -0
- package/lib/inventory/protobom.js +62 -89
- package/lib/inventory/protobomLoader.js +4 -0
- package/lib/inventory/purl.js +152 -3
- package/lib/inventory/rustFormulationParser.js +1 -1
- package/lib/inventory/sbomDocument.js +2 -70
- package/lib/inventory/source.js +47 -23
- package/lib/inventory/stylePackageRefs.js +41 -0
- package/lib/inventory/svelteUtils.js +524 -0
- package/lib/inventory/traceRunner.js +210 -21
- package/lib/managers/binary.js +115 -24
- package/lib/managers/docker.js +440 -20
- package/lib/managers/oci.js +39 -1
- package/lib/parsers/cmakeLists.js +452 -0
- package/lib/parsers/huggingfaceUtils.js +15 -7
- package/lib/parsers/largeJson.js +454 -0
- package/lib/parsers/npmrc.js +19 -1
- package/lib/parsers/onnx.js +294 -0
- package/lib/parsers/safetensors.js +114 -0
- package/lib/stages/postgen/introspection/markers.js +29 -6
- package/lib/stages/postgen/postgen.js +237 -16
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +462 -0
- package/lib/validator/bomValidator.js +6 -16
- package/lib/validator/index.js +48 -10
- package/lib/validator/reporters/console.js +3 -0
- package/lib/validator/reporters/json.js +1 -0
- package/lib/validator/reporters/sarif.js +7 -0
- package/package.json +27 -27
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +2 -1
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +33 -1
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +2 -2
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jsBom.d.ts +23 -0
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts +33 -0
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts +88 -8
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/activity.d.ts.map +1 -1
- package/types/lib/core/env.d.ts +21 -0
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts +55 -0
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/metadataProperties.d.ts +39 -0
- package/types/lib/core/metadataProperties.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts +6 -2
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/userAgent.d.ts +56 -0
- package/types/lib/core/userAgent.d.ts.map +1 -0
- package/types/lib/ecosystems/bunutils.d.ts +12 -5
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
- package/types/lib/ecosystems/cargoCache.d.ts +75 -0
- package/types/lib/ecosystems/cargoCache.d.ts.map +1 -0
- package/types/lib/ecosystems/caxa.d.ts +14 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -1
- package/types/lib/ecosystems/cmakeResolver.d.ts +23 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/cppEvidence.d.ts +2 -2
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts +15 -1
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +40 -4
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts +5 -2
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts +86 -0
- package/types/lib/ecosystems/kosi.d.ts.map +1 -0
- package/types/lib/ecosystems/npmutils.d.ts +42 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-crystal.d.ts +27 -0
- package/types/lib/ecosystems/parsers-crystal.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts +19 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-elm.d.ts +79 -0
- package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-go.d.ts +10 -0
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +10 -4
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-julia.d.ts +57 -0
- package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-lua.d.ts +50 -0
- package/types/lib/ecosystems/parsers-lua.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-misc.d.ts +90 -3
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-nim.d.ts +43 -0
- package/types/lib/ecosystems/parsers-nim.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-opam.d.ts +31 -0
- package/types/lib/ecosystems/parsers-opam.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-perl.d.ts +36 -0
- package/types/lib/ecosystems/parsers-perl.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-r.d.ts +35 -0
- package/types/lib/ecosystems/parsers-r.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rebar.d.ts +42 -0
- package/types/lib/ecosystems/parsers-rebar.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rust.d.ts +199 -0
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-spack.d.ts +33 -0
- package/types/lib/ecosystems/parsers-spack.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-stack.d.ts +35 -0
- package/types/lib/ecosystems/parsers-stack.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-terraform.d.ts +34 -0
- package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -0
- package/types/lib/ecosystems/pythonutils.d.ts +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +143 -2
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts +13 -0
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +81 -2
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/swiftsem.d.ts +280 -15
- package/types/lib/evinser/swiftsem.d.ts.map +1 -1
- package/types/lib/helpers/agenticToolutils.d.ts +87 -0
- package/types/lib/helpers/agenticToolutils.d.ts.map +1 -0
- package/types/lib/helpers/bomSigner.d.ts +106 -13
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/aiInventory.d.ts.map +1 -1
- package/types/lib/inventory/analyzer.d.ts.map +1 -1
- package/types/lib/inventory/atomUtils.d.ts +145 -3
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +4 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/cbomutils.d.ts.map +1 -1
- package/types/lib/inventory/cdxrs.d.ts +8 -3
- package/types/lib/inventory/cdxrs.d.ts.map +1 -1
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/depsUtils.d.ts +15 -0
- package/types/lib/inventory/depsUtils.d.ts.map +1 -1
- package/types/lib/inventory/display.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +87 -1
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/fetchBatch.d.ts +34 -0
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/fetchRate.d.ts +9 -6
- package/types/lib/inventory/fetchRate.d.ts.map +1 -1
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
- package/types/lib/inventory/jvmToolEnv.d.ts +5 -4
- package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -1
- package/types/lib/inventory/mcpServerManifest.d.ts +19 -0
- package/types/lib/inventory/mcpServerManifest.d.ts.map +1 -0
- package/types/lib/inventory/mcpbBundle.d.ts +19 -0
- package/types/lib/inventory/mcpbBundle.d.ts.map +1 -0
- package/types/lib/inventory/plugins.d.ts.map +1 -1
- package/types/lib/inventory/protobom.d.ts +18 -13
- package/types/lib/inventory/protobom.d.ts.map +1 -1
- package/types/lib/inventory/protobomLoader.d.ts.map +1 -1
- package/types/lib/inventory/purl.d.ts +71 -2
- package/types/lib/inventory/purl.d.ts.map +1 -1
- package/types/lib/inventory/sbomDocument.d.ts.map +1 -1
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/stylePackageRefs.d.ts +17 -0
- package/types/lib/inventory/stylePackageRefs.d.ts.map +1 -0
- package/types/lib/inventory/svelteUtils.d.ts +124 -0
- package/types/lib/inventory/svelteUtils.d.ts.map +1 -0
- package/types/lib/inventory/traceRunner.d.ts +47 -1
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +30 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +29 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +14 -0
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/parsers/cmakeLists.d.ts +76 -0
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts +8 -1
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
- package/types/lib/parsers/largeJson.d.ts +52 -0
- package/types/lib/parsers/largeJson.d.ts.map +1 -0
- package/types/lib/parsers/npmrc.d.ts +5 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -1
- package/types/lib/parsers/onnx.d.ts +28 -0
- package/types/lib/parsers/onnx.d.ts.map +1 -0
- package/types/lib/parsers/safetensors.d.ts +22 -0
- package/types/lib/parsers/safetensors.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/markers.d.ts +3 -2
- package/types/lib/stages/postgen/introspection/markers.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +33 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +10 -1
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/console.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -1
|
@@ -7,7 +7,12 @@ import { Purl } from "@cdxgen/cdx-purl";
|
|
|
7
7
|
import { DEBUG_MODE } from "../core/activity.js";
|
|
8
8
|
import { shouldFetchLicense, shouldFetchVCS } from "../core/env.js";
|
|
9
9
|
import { safeExistsSync } from "../core/fs.js";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
applyPurl,
|
|
12
|
+
canonicalPurlFromLooseString,
|
|
13
|
+
tryBuildPurl,
|
|
14
|
+
tryParsePurl,
|
|
15
|
+
} from "../inventory/purl.js";
|
|
11
16
|
import {
|
|
12
17
|
_clearMetadataCache,
|
|
13
18
|
getGoPkgLicense,
|
|
@@ -443,6 +448,23 @@ function _addGoComponentEvidence(component, goModFile, confidence = 0.8) {
|
|
|
443
448
|
return component;
|
|
444
449
|
}
|
|
445
450
|
|
|
451
|
+
/**
|
|
452
|
+
* Build the purl of one `module@version` token from `go mod graph` output.
|
|
453
|
+
*
|
|
454
|
+
* The version is written the way Go prints it, so `+incompatible` and the build
|
|
455
|
+
* metadata of a pseudo-version are unescaped. Reading the token strictly would
|
|
456
|
+
* reject it and leave a reference that keeps the module path's upper-case
|
|
457
|
+
* letters, which then never matches the lower-cased component and drops the
|
|
458
|
+
* dependency edge.
|
|
459
|
+
*
|
|
460
|
+
* @param {string} token Module path, optionally followed by `@version`
|
|
461
|
+
* @returns {Purl|null} Parsed purl, or null when the token forms no valid golang purl
|
|
462
|
+
*/
|
|
463
|
+
function goModGraphTokenPurl(token) {
|
|
464
|
+
const canonical = canonicalPurlFromLooseString(`pkg:golang/${token}`);
|
|
465
|
+
return canonical ? Purl.parse(canonical) : null;
|
|
466
|
+
}
|
|
467
|
+
|
|
446
468
|
/**
|
|
447
469
|
* Parse go mod graph
|
|
448
470
|
*
|
|
@@ -512,22 +534,20 @@ export async function parseGoModGraph(
|
|
|
512
534
|
// cdx-purl requires a namespace. Use the raw ref when parsing fails.
|
|
513
535
|
let sourceRefString;
|
|
514
536
|
let sourceName = tmpA[0].split("@")[0];
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
sourcePurl = Purl.parse(`pkg:golang/${tmpA[0]}`);
|
|
537
|
+
const sourcePurl = goModGraphTokenPurl(tmpA[0]);
|
|
538
|
+
if (sourcePurl) {
|
|
518
539
|
sourceRefString = decodeURIComponent(sourcePurl.toString());
|
|
519
540
|
sourceName = `${sourcePurl.namespace ? `${sourcePurl.namespace}/` : ""}${sourcePurl.name}`;
|
|
520
|
-
}
|
|
541
|
+
} else {
|
|
521
542
|
sourceRefString = `pkg:golang/${tmpA[0]}`;
|
|
522
543
|
}
|
|
523
544
|
let dependsRefString;
|
|
524
545
|
let dependsName = tmpA[1].split("@")[0];
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
dependsPurl = Purl.parse(`pkg:golang/${tmpA[1]}`);
|
|
546
|
+
const dependsPurl = goModGraphTokenPurl(tmpA[1]);
|
|
547
|
+
if (dependsPurl) {
|
|
528
548
|
dependsRefString = decodeURIComponent(dependsPurl.toString());
|
|
529
549
|
dependsName = `${dependsPurl.namespace ? `${dependsPurl.namespace}/` : ""}${dependsPurl.name}`;
|
|
530
|
-
}
|
|
550
|
+
} else {
|
|
531
551
|
dependsRefString = `pkg:golang/${tmpA[1]}`;
|
|
532
552
|
}
|
|
533
553
|
// Since go mod graph over-reports direct dependencies we use the existing list
|
|
@@ -683,6 +703,24 @@ export function parseGoModWhy(rawOutput) {
|
|
|
683
703
|
return undefined;
|
|
684
704
|
}
|
|
685
705
|
|
|
706
|
+
/**
|
|
707
|
+
* Reports whether `go mod why -m` output says the main module does not need
|
|
708
|
+
* the module. go prints `(main module does not need module X)`, or
|
|
709
|
+
* `(main module does not need to vendor module X)` with `-vendor`, and exits
|
|
710
|
+
* with status 0 either way.
|
|
711
|
+
*
|
|
712
|
+
* @param {string} rawOutput Output from go mod why
|
|
713
|
+
* @returns {boolean} True when go reports the module as not needed
|
|
714
|
+
*/
|
|
715
|
+
export function isGoModWhyNotNeeded(rawOutput) {
|
|
716
|
+
if (typeof rawOutput !== "string") {
|
|
717
|
+
return false;
|
|
718
|
+
}
|
|
719
|
+
return rawOutput
|
|
720
|
+
.split("\n")
|
|
721
|
+
.some((line) => line.trim().startsWith("(main module does not need "));
|
|
722
|
+
}
|
|
723
|
+
|
|
686
724
|
/**
|
|
687
725
|
* Parse go sum data
|
|
688
726
|
* @param {string} gosumData Content of go.sum
|
|
@@ -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 {
|
|
@@ -914,11 +914,16 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
|
|
|
914
914
|
// A package.json need not declare a version, and npm installs without
|
|
915
915
|
// one, so the root of a lockfile can reach here with none. A purl carries
|
|
916
916
|
// no version rather than an empty one.
|
|
917
|
-
purlString =
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
917
|
+
purlString = (
|
|
918
|
+
projectGroup
|
|
919
|
+
? build({
|
|
920
|
+
type: "npm",
|
|
921
|
+
namespace: projectGroup,
|
|
922
|
+
name: projectName,
|
|
923
|
+
version: projectVersion || null,
|
|
924
|
+
})
|
|
925
|
+
: npmPurl(projectName, projectVersion)
|
|
926
|
+
).replace(/%2F/g, "/");
|
|
922
927
|
pkg = {
|
|
923
928
|
author: authorString,
|
|
924
929
|
group: options.projectGroup || "",
|
|
@@ -1778,17 +1783,15 @@ function _resolveYarnDependencyBomRef(
|
|
|
1778
1783
|
packageNameToUse,
|
|
1779
1784
|
);
|
|
1780
1785
|
if (matchingWorkspace) {
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1786
|
+
// The workspace reference may be an escaped purl, so its version is read
|
|
1787
|
+
// through the purl parser rather than cut out of the string.
|
|
1788
|
+
resolvedVersion =
|
|
1789
|
+
parsePurlLoose(matchingWorkspace)?.version || resolvedVersion;
|
|
1785
1790
|
}
|
|
1786
1791
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
}
|
|
1791
|
-
return decodeURIComponent(Purl.parse(purlPart).toString());
|
|
1792
|
+
return decodeURIComponent(
|
|
1793
|
+
npmPurl(packageNameToUse, resolvedVersion?.length ? resolvedVersion : null),
|
|
1794
|
+
);
|
|
1792
1795
|
}
|
|
1793
1796
|
|
|
1794
1797
|
function _collectYarnRootDependencyRefs(
|
|
@@ -1919,7 +1922,7 @@ function _markYarnDependencyScopeClosures(
|
|
|
1919
1922
|
* @param {Object} parentComponent parent component
|
|
1920
1923
|
* @param {Array[String]} workspacePackages Workspace packages
|
|
1921
1924
|
* @param {Object} workspaceSrcFiles Workspace package.json files
|
|
1922
|
-
* @param {Object}
|
|
1925
|
+
* @param {Object} workspaceDirectDeps Declared dependencies (name to range) of each workspace package
|
|
1923
1926
|
* @param {Object} depsWorkspaceRefs Workspace references for each dependency
|
|
1924
1927
|
*/
|
|
1925
1928
|
export async function parseYarnLock(
|
|
@@ -1927,12 +1930,14 @@ export async function parseYarnLock(
|
|
|
1927
1930
|
parentComponent = null,
|
|
1928
1931
|
workspacePackages = [],
|
|
1929
1932
|
workspaceSrcFiles = {},
|
|
1930
|
-
|
|
1933
|
+
workspaceDirectDeps = {},
|
|
1931
1934
|
depsWorkspaceRefs = {},
|
|
1932
1935
|
) {
|
|
1933
1936
|
let pkgList = [];
|
|
1934
1937
|
const dependenciesList = [];
|
|
1935
1938
|
const depKeys = {};
|
|
1939
|
+
// The lock keys and the resolved version required to solve the dependency tree
|
|
1940
|
+
let identMap = {};
|
|
1936
1941
|
let yarnRootRefs = _createYarnRootDependencyRefs();
|
|
1937
1942
|
const yarnOptionalDependencyRefs = new Set();
|
|
1938
1943
|
const npmrcConfig = loadNpmrcConfig(dirname(yarnLockFile));
|
|
@@ -1951,8 +1956,7 @@ export async function parseYarnLock(
|
|
|
1951
1956
|
const pkgAddedMap = {};
|
|
1952
1957
|
// Map to track workspace package PURL replacements from 0.0.0-use.local to actual versions
|
|
1953
1958
|
const workspacePurlMap = {};
|
|
1954
|
-
|
|
1955
|
-
const identMap = yarnLockToIdentMap(lockData);
|
|
1959
|
+
identMap = yarnLockToIdentMap(lockData);
|
|
1956
1960
|
yarnRootRefs = _collectYarnRootDependencyRefs(
|
|
1957
1961
|
yarnLockFile,
|
|
1958
1962
|
identMap,
|
|
@@ -2020,8 +2024,8 @@ export async function parseYarnLock(
|
|
|
2020
2024
|
const actualWorkspacePurl = workspacePackages.find(
|
|
2021
2025
|
(wp) =>
|
|
2022
2026
|
wp.startsWith(expectedPurlStart) ||
|
|
2023
|
-
wp.
|
|
2024
|
-
|
|
2027
|
+
wp.startsWith(
|
|
2028
|
+
`${npmPurl(group ? `${group}/${name}` : name)}@`,
|
|
2025
2029
|
),
|
|
2026
2030
|
);
|
|
2027
2031
|
// Also check if this package already exists in pkgList with a real version
|
|
@@ -2286,23 +2290,21 @@ export async function parseYarnLock(
|
|
|
2286
2290
|
if (DEBUG_MODE) {
|
|
2287
2291
|
console.log(`Processing workspace package: "${workspacePkg}"`);
|
|
2288
2292
|
}
|
|
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);
|
|
2293
|
+
// Workspace references arrive both escaped (built by cdx-purl) and in
|
|
2294
|
+
// the decoded bom-ref form, so they are split structurally and
|
|
2295
|
+
// rebuilt. Copying the version text across forms is what turned
|
|
2296
|
+
// `3.0.0+ws` into `3.0.0%252Bws`.
|
|
2297
|
+
const workspaceParts = parsePurlLoose(workspacePkg);
|
|
2298
|
+
if (!workspaceParts) {
|
|
2299
|
+
continue;
|
|
2305
2300
|
}
|
|
2301
|
+
const purlObj = new Purl({
|
|
2302
|
+
type: "npm",
|
|
2303
|
+
namespace: workspaceParts.namespace,
|
|
2304
|
+
name: workspaceParts.name,
|
|
2305
|
+
version: workspaceParts.version,
|
|
2306
|
+
subpath: workspaceParts.subpath,
|
|
2307
|
+
});
|
|
2306
2308
|
|
|
2307
2309
|
// Create the workspace component using the properly parsed PURL
|
|
2308
2310
|
const workspaceComponent = {
|
|
@@ -2405,6 +2407,41 @@ export async function parseYarnLock(
|
|
|
2405
2407
|
}
|
|
2406
2408
|
}
|
|
2407
2409
|
}
|
|
2410
|
+
// A yarn v1 lock file has no entries for workspace packages, so a member
|
|
2411
|
+
// would otherwise have no dependency entry and nothing would reach it.
|
|
2412
|
+
// Each member gets one built from the dependencies its own package.json
|
|
2413
|
+
// declares; the root's entry, built from every dependency entry, then
|
|
2414
|
+
// includes the member too. A lock file that already recorded the member
|
|
2415
|
+
// (yarn berry) keeps the entry it produced.
|
|
2416
|
+
const recordedRefs = new Set(dependenciesList.map((d) => d.ref));
|
|
2417
|
+
for (const workspacePkg of workspacePackages) {
|
|
2418
|
+
const workspaceRef = decodeURIComponent(workspacePkg);
|
|
2419
|
+
if (
|
|
2420
|
+
recordedRefs.has(workspaceRef) ||
|
|
2421
|
+
!pkgList.some((pkg) => pkg["bom-ref"] === workspaceRef)
|
|
2422
|
+
) {
|
|
2423
|
+
continue;
|
|
2424
|
+
}
|
|
2425
|
+
const dependsOn = new Set();
|
|
2426
|
+
for (const [depName, depRange] of Object.entries(
|
|
2427
|
+
workspaceDirectDeps?.[workspacePkg] || {},
|
|
2428
|
+
)) {
|
|
2429
|
+
const depRef = _resolveYarnDependencyBomRef(
|
|
2430
|
+
depName,
|
|
2431
|
+
String(depRange),
|
|
2432
|
+
identMap,
|
|
2433
|
+
workspacePackages,
|
|
2434
|
+
);
|
|
2435
|
+
if (depRef && depRef !== workspaceRef) {
|
|
2436
|
+
dependsOn.add(depRef);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
dependenciesList.push({
|
|
2440
|
+
ref: workspaceRef,
|
|
2441
|
+
dependsOn: [...dependsOn].sort(),
|
|
2442
|
+
});
|
|
2443
|
+
recordedRefs.add(workspaceRef);
|
|
2444
|
+
}
|
|
2408
2445
|
}
|
|
2409
2446
|
|
|
2410
2447
|
_markYarnDependencyScopeClosures(
|
|
@@ -2646,7 +2683,10 @@ export function stripPnpmPeerSuffix(version) {
|
|
|
2646
2683
|
* {@link stripPnpmPeerSuffix}.
|
|
2647
2684
|
*
|
|
2648
2685
|
* @param {string|object} depPkg Dependency version string or package object.
|
|
2649
|
-
* @param {string} relativePath Base path for resolving link/file references
|
|
2686
|
+
* @param {string} relativePath Base path for resolving link/file references:
|
|
2687
|
+
* the directory of the importer that declares the dependency. Without it the
|
|
2688
|
+
* path is tried against the working directory, which only works when cdxgen
|
|
2689
|
+
* runs from the lock file's directory.
|
|
2650
2690
|
* @returns {Promise<string|undefined>} The resolved published version.
|
|
2651
2691
|
*/
|
|
2652
2692
|
export async function getVersionNumPnpm(depPkg, relativePath) {
|
|
@@ -2685,6 +2725,25 @@ export async function getVersionNumPnpm(depPkg, relativePath) {
|
|
|
2685
2725
|
return version;
|
|
2686
2726
|
}
|
|
2687
2727
|
|
|
2728
|
+
/**
|
|
2729
|
+
* Split the package name of a pnpm `file:` lock key into scope and name.
|
|
2730
|
+
*
|
|
2731
|
+
* @param {string} fullName Package name as written before `@file:`, eg `@scope/pkg`
|
|
2732
|
+
* @returns {{group: string, name: string}} Scope (with its `@`) and bare name
|
|
2733
|
+
*/
|
|
2734
|
+
function splitPnpmFilePackageName(fullName) {
|
|
2735
|
+
if (fullName.startsWith("@")) {
|
|
2736
|
+
const slash = fullName.indexOf("/");
|
|
2737
|
+
if (slash > 0) {
|
|
2738
|
+
return {
|
|
2739
|
+
group: fullName.slice(0, slash),
|
|
2740
|
+
name: fullName.slice(slash + 1),
|
|
2741
|
+
};
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
return { group: "", name: fullName };
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2688
2747
|
/**
|
|
2689
2748
|
* Resolve a pnpm dependency to its PURL string.
|
|
2690
2749
|
*
|
|
@@ -2723,11 +2782,16 @@ export async function getPnpmDepPurl(
|
|
|
2723
2782
|
}
|
|
2724
2783
|
gitPkgRefs[versionObj.version] = { group, name, version };
|
|
2725
2784
|
} else {
|
|
2785
|
+
const rawSpec =
|
|
2786
|
+
typeof versionObj?.version === "string" ? versionObj.version : "";
|
|
2726
2787
|
version = await getVersionNumPnpm(depPkg, relativePath);
|
|
2727
2788
|
const gitEntry =
|
|
2728
2789
|
gitPkgRefs[packageName] ||
|
|
2729
2790
|
gitPkgRefs[version] ||
|
|
2730
|
-
gitPkgRefs[normalizePnpmLockKey(`${packageName}@${version}`)]
|
|
2791
|
+
gitPkgRefs[normalizePnpmLockKey(`${packageName}@${version}`)] ||
|
|
2792
|
+
(rawSpec.startsWith("file:")
|
|
2793
|
+
? gitPkgRefs[normalizePnpmLockKey(`${packageName}@${rawSpec}`)]
|
|
2794
|
+
: undefined);
|
|
2731
2795
|
if (gitEntry) {
|
|
2732
2796
|
group = gitEntry.group;
|
|
2733
2797
|
name = gitEntry.name;
|
|
@@ -2980,7 +3044,8 @@ export async function pnpmMetadata(pkgList, lockFilePath) {
|
|
|
2980
3044
|
// Silently ignore parsing errors for individual packages
|
|
2981
3045
|
if (DEBUG_MODE) {
|
|
2982
3046
|
console.log(
|
|
2983
|
-
|
|
3047
|
+
"Failed to parse package.json at %s:",
|
|
3048
|
+
packageJsonPath,
|
|
2984
3049
|
error.message,
|
|
2985
3050
|
);
|
|
2986
3051
|
}
|
|
@@ -3148,6 +3213,33 @@ export async function parsePnpmLock(
|
|
|
3148
3213
|
npmrcConfig,
|
|
3149
3214
|
),
|
|
3150
3215
|
);
|
|
3216
|
+
// A `file:` package is keyed by its path (`localdep@file:localdep.tgz`) and
|
|
3217
|
+
// pnpm copies the manifest version into its `packages` entry. Registering
|
|
3218
|
+
// it lets an importer that names the path resolve to the same ref the
|
|
3219
|
+
// package loop below builds, instead of a version made from the path.
|
|
3220
|
+
if (lockfileVersion >= 9) {
|
|
3221
|
+
for (const [lockKey, pkgEntry] of Object.entries(
|
|
3222
|
+
yamlObj.packages || {},
|
|
3223
|
+
)) {
|
|
3224
|
+
const fileAt = lockKey.indexOf("@file:", 1);
|
|
3225
|
+
if (fileAt < 1 || !pkgEntry?.version) {
|
|
3226
|
+
continue;
|
|
3227
|
+
}
|
|
3228
|
+
const normalizedKey = normalizePnpmLockKey(lockKey);
|
|
3229
|
+
if (gitPkgRefs[normalizedKey]) {
|
|
3230
|
+
continue;
|
|
3231
|
+
}
|
|
3232
|
+
const { group, name } = splitPnpmFilePackageName(
|
|
3233
|
+
lockKey.slice(0, fileAt),
|
|
3234
|
+
);
|
|
3235
|
+
gitPkgRefs[normalizedKey] = {
|
|
3236
|
+
group,
|
|
3237
|
+
name,
|
|
3238
|
+
version: String(pkgEntry.version),
|
|
3239
|
+
vcsUrl: lockKey.slice(fileAt + 1),
|
|
3240
|
+
};
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3151
3243
|
// This logic matches the pnpm list command to include only direct dependencies
|
|
3152
3244
|
if (ppurl !== "" && yamlObj?.importers) {
|
|
3153
3245
|
// In lock file version 6, direct dependencies is under importers
|
|
@@ -3184,7 +3276,7 @@ export async function parsePnpmLock(
|
|
|
3184
3276
|
rootDevDeps[rdk],
|
|
3185
3277
|
rdk,
|
|
3186
3278
|
gitPkgRefs,
|
|
3187
|
-
|
|
3279
|
+
pnpmLockDir,
|
|
3188
3280
|
githubServerHost,
|
|
3189
3281
|
npmrcConfig,
|
|
3190
3282
|
);
|
|
@@ -3206,7 +3298,7 @@ export async function parsePnpmLock(
|
|
|
3206
3298
|
rootOptionalDeps[rdk] || rootPeerDeps[rdk],
|
|
3207
3299
|
rdk,
|
|
3208
3300
|
gitPkgRefs,
|
|
3209
|
-
|
|
3301
|
+
pnpmLockDir,
|
|
3210
3302
|
githubServerHost,
|
|
3211
3303
|
npmrcConfig,
|
|
3212
3304
|
);
|
|
@@ -3229,7 +3321,7 @@ export async function parsePnpmLock(
|
|
|
3229
3321
|
rootDirectDeps[dk],
|
|
3230
3322
|
dk,
|
|
3231
3323
|
gitPkgRefs,
|
|
3232
|
-
|
|
3324
|
+
pnpmLockDir,
|
|
3233
3325
|
githubServerHost,
|
|
3234
3326
|
npmrcConfig,
|
|
3235
3327
|
);
|
|
@@ -3340,7 +3432,7 @@ export async function parsePnpmLock(
|
|
|
3340
3432
|
versionObj,
|
|
3341
3433
|
cdk,
|
|
3342
3434
|
gitPkgRefs,
|
|
3343
|
-
importedComponentName,
|
|
3435
|
+
join(pnpmLockDir, importedComponentName),
|
|
3344
3436
|
githubServerHost,
|
|
3345
3437
|
npmrcConfig,
|
|
3346
3438
|
);
|
|
@@ -3357,7 +3449,10 @@ export async function parsePnpmLock(
|
|
|
3357
3449
|
}
|
|
3358
3450
|
}
|
|
3359
3451
|
for (const cdk of Object.keys(componentDevDeps)) {
|
|
3360
|
-
const version = await getVersionNumPnpm(
|
|
3452
|
+
const version = await getVersionNumPnpm(
|
|
3453
|
+
componentDevDeps[cdk],
|
|
3454
|
+
join(pnpmLockDir, importedComponentName),
|
|
3455
|
+
);
|
|
3361
3456
|
const dpurl = build({
|
|
3362
3457
|
type: "npm",
|
|
3363
3458
|
namespace: "" || null,
|
|
@@ -3375,6 +3470,7 @@ export async function parsePnpmLock(
|
|
|
3375
3470
|
})) {
|
|
3376
3471
|
const version = await getVersionNumPnpm(
|
|
3377
3472
|
componentOptionalDeps[cdk] || componentPeerDeps[cdk],
|
|
3473
|
+
join(pnpmLockDir, importedComponentName),
|
|
3378
3474
|
);
|
|
3379
3475
|
const dpurl = build({
|
|
3380
3476
|
type: "npm",
|
|
@@ -3399,6 +3495,11 @@ export async function parsePnpmLock(
|
|
|
3399
3495
|
// snapshots is a new key under lockfile version 9
|
|
3400
3496
|
const snapshots = yamlObj.snapshots || {};
|
|
3401
3497
|
const pkgKeys = { ...Object.keys(packages), ...Object.keys(snapshots) };
|
|
3498
|
+
// A lock entry named `__proto__` is not a real package: emitting it as a
|
|
3499
|
+
// component produces SBOM data that breaks naive JSON consumers, and the
|
|
3500
|
+
// name can never come from the npm registry. Legitimate names such as
|
|
3501
|
+
// `constructor` or `prototype` are unaffected.
|
|
3502
|
+
const protoLockKey = /(^|\/)__proto__(@|$)/;
|
|
3402
3503
|
for (const k in pkgKeys) {
|
|
3403
3504
|
// Eg: @babel/code-frame/7.10.1
|
|
3404
3505
|
// In lockfileVersion 6, /@babel/code-frame@7.18.6
|
|
@@ -3407,6 +3508,9 @@ export async function parsePnpmLock(
|
|
|
3407
3508
|
if (lockfileVersion >= 6 && fullName.includes("(")) {
|
|
3408
3509
|
fullName = fullName.split("(")[0];
|
|
3409
3510
|
}
|
|
3511
|
+
if (protoLockKey.test(pkgKeys[k]) || protoLockKey.test(fullName)) {
|
|
3512
|
+
continue;
|
|
3513
|
+
}
|
|
3410
3514
|
const parts = fullName.split("/");
|
|
3411
3515
|
const packageNode =
|
|
3412
3516
|
packages[pkgKeys[k]] ||
|
|
@@ -3465,9 +3569,17 @@ export async function parsePnpmLock(
|
|
|
3465
3569
|
}
|
|
3466
3570
|
let opurlString;
|
|
3467
3571
|
if (vers.includes("@")) {
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3572
|
+
// An aliased optional dependency records `name@version`, and the
|
|
3573
|
+
// version may carry semver build metadata that must be escaped.
|
|
3574
|
+
const aliasParts = parsePurlLoose(`pkg:npm/${vers}`);
|
|
3575
|
+
opurlString = aliasParts
|
|
3576
|
+
? npmPurl(
|
|
3577
|
+
aliasParts.namespace
|
|
3578
|
+
? `${aliasParts.namespace}/${aliasParts.name}`
|
|
3579
|
+
: aliasParts.name,
|
|
3580
|
+
aliasParts.version,
|
|
3581
|
+
)
|
|
3582
|
+
: npmPurl(opkgName, vers);
|
|
3471
3583
|
} else {
|
|
3472
3584
|
opurlString = npmPurl(opkgName, vers);
|
|
3473
3585
|
}
|
|
@@ -3536,8 +3648,17 @@ export async function parsePnpmLock(
|
|
|
3536
3648
|
possibleHttpParts[possibleHttpParts.length - 1].startsWith("file")
|
|
3537
3649
|
) {
|
|
3538
3650
|
srcUrl = possibleHttpParts[possibleHttpParts.length - 1];
|
|
3539
|
-
name =
|
|
3540
|
-
|
|
3651
|
+
({ group, name } = splitPnpmFilePackageName(
|
|
3652
|
+
fullName.replace(`@${srcUrl}`, ""),
|
|
3653
|
+
));
|
|
3654
|
+
// The key names the path, not a version. pnpm copies the version
|
|
3655
|
+
// from the package's own manifest into its `packages` entry, and
|
|
3656
|
+
// that may carry semver build metadata (`2.0.0+local`).
|
|
3657
|
+
version = String(
|
|
3658
|
+
packages[pkgKeys[k]]?.version ||
|
|
3659
|
+
packages[fullName]?.version ||
|
|
3660
|
+
"",
|
|
3661
|
+
);
|
|
3541
3662
|
} else {
|
|
3542
3663
|
group = parts.length > 1 ? parts[0] : "";
|
|
3543
3664
|
const tmpA = parts[parts.length - 1].split("@");
|