From 8f6b1ed5cffd4f84b6d3f11fab42948814ab804e Mon Sep 17 00:00:00 2001 From: Fernando Rojo Date: Thu, 13 Mar 2025 12:11:35 -0600 Subject: [PATCH 1/2] Fix link version parsing in pnpm9 --- .../pnpm/Pnpm9Detector.cs | 5 +- .../PnpmDetectorTests.cs | 71 +++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.ComponentDetection.Detectors/pnpm/Pnpm9Detector.cs b/src/Microsoft.ComponentDetection.Detectors/pnpm/Pnpm9Detector.cs index a5903ab63..1326f5770 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pnpm/Pnpm9Detector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pnpm/Pnpm9Detector.cs @@ -73,11 +73,12 @@ private void ProcessDependencyList(ISingleFileComponentRecorder singleFileCompon { var pnpmDependencyPath = this.pnpmParsingUtilities.ReconstructPnpmDependencyPath(name, dep.Version); var (component, package) = components[pnpmDependencyPath]; + var (_, packageVersion) = this.pnpmParsingUtilities.ExtractNameAndVersionFromPnpmPackagePath(pnpmDependencyPath); // Lockfile v9 apparently removed the tagging of dev dependencies in the lockfile, so we revert to using the dependency tree to establish dev dependency state. // At this point, the root dependencies are marked according to which dependency group they are declared in the lockfile itself. // Ignore "file:" and "link:" as these are local packages. - var isFileOrLink = this.IsFileOrLink(dep.Version); + var isFileOrLink = this.IsFileOrLink(packageVersion); if (!isFileOrLink) { singleFileComponentRecorder.RegisterUsage(component, isExplicitReferencedDependency: true, isDevelopmentDependency: isDevelopmentDependency); @@ -102,7 +103,7 @@ private void ProcessIndirectDependencies(ISingleFileComponentRecorder singleFile foreach (var (name, version) in dependencies ?? Enumerable.Empty>()) { // Ignore "file:" and "link:" as these are local packages. - if (version.StartsWith(PnpmConstants.PnpmLinkDependencyPath) || version.StartsWith(PnpmConstants.PnpmFileDependencyPath)) + if (this.IsFileOrLink(version)) { continue; } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PnpmDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PnpmDetectorTests.cs index 3f212e96e..9554dd879 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PnpmDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PnpmDetectorTests.cs @@ -921,6 +921,77 @@ public async Task TestPnpmDetector_V9_GoodLockVersion_HttpDependenciesAreNotRegi parentComponent => parentComponent.Name == "sampleDependency"); } + [TestMethod] + public async Task TestPnpmDetector_V9_GoodLockVersion_HttpsDependenciesAreNotRegistered() + { + var yamlFile = @" +lockfileVersion: '9.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false +importers: + .: + dependencies: + sampleDependency: + specifier: ^1.1.1 + version: 1.1.1 + '@sample_dependency/sampleHttpDependency': + specifier: https://samplePackage/tar.gz/32f550d3b3bdb1b781aabe100683311cd982c98e + version: sample@https://samplePackage/tar.gz/32f550d3b3bdb1b781aabe100683311cd982c98e + SampleLinkDependency: + specifier: workspace:* + version: link:SampleLinkDependency +packages: + sampleDependency@1.1.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + sampleIndirectDependency2@2.2.2: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + sampleIndirectDependency@3.3.3: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + sample@https://samplePackage/tar.gz/32f550d3b3bdb1b781aabe100683311cd982c98e: + resolution: {tarball: https://samplePackage/tar.gz/32f550d3b3bdb1b781aabe100683311cd982c98e} + version: 1.3.3 + +snapshots: + sampleDependency@1.1.1: + dependencies: + sampleIndirectDependency: 3.3.3 + sampleIndirectDependency2: 2.2.2 + sampleIndirectDependency2@2.2.2: {} + sampleIndirectDependency@3.3.3: {} + sample@https://samplePackage/tar.gz/32f550d3b3bdb1b781aabe100683311cd982c98e': {} +"; + + var (scanResult, componentRecorder) = await this.DetectorTestUtility + .WithFile("pnpm-lock.yaml", yamlFile) + .ExecuteDetectorAsync(); + + scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + detectedComponents.Should().HaveCount(3); + var npmComponents = detectedComponents.Select(x => new { Component = x.Component as NpmComponent, DetectedComponent = x }); + npmComponents.Should().Contain(x => x.Component.Name == "sampleDependency" && x.Component.Version == "1.1.1"); + npmComponents.Should().Contain(x => x.Component.Name == "sampleIndirectDependency2" && x.Component.Version == "2.2.2"); + npmComponents.Should().Contain(x => x.Component.Name == "sampleIndirectDependency" && x.Component.Version == "3.3.3"); + + var noDevDependencyComponent = npmComponents.First(x => x.Component.Name == "sampleDependency"); + var indirectDependencyComponent2 = npmComponents.First(x => x.Component.Name == "sampleIndirectDependency2"); + var indirectDependencyComponent = npmComponents.First(x => x.Component.Name == "sampleIndirectDependency"); + + componentRecorder.GetEffectiveDevDependencyValue(noDevDependencyComponent.Component.Id).Should().BeFalse(); + componentRecorder.GetEffectiveDevDependencyValue(indirectDependencyComponent2.Component.Id).Should().BeFalse(); + componentRecorder.GetEffectiveDevDependencyValue(indirectDependencyComponent.Component.Id).Should().BeFalse(); + componentRecorder.AssertAllExplicitlyReferencedComponents( + indirectDependencyComponent.Component.Id, + parentComponent => parentComponent.Name == "sampleDependency"); + componentRecorder.AssertAllExplicitlyReferencedComponents( + indirectDependencyComponent2.Component.Id, + parentComponent => parentComponent.Name == "sampleDependency"); + } + [TestMethod] public async Task TestPnpmDetector_V9_GoodLockVersion_MissingSnapshotsSuccess() { From 85e8c0c5cd33b820ceff4d862181581385a393e8 Mon Sep 17 00:00:00 2001 From: Fernando Rojo Date: Thu, 13 Mar 2025 12:39:14 -0600 Subject: [PATCH 2/2] bump detector version --- .../pnpm/PnpmComponentDetectorFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmComponentDetectorFactory.cs b/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmComponentDetectorFactory.cs index 2bc3e7880..5261921f1 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmComponentDetectorFactory.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmComponentDetectorFactory.cs @@ -41,7 +41,7 @@ public PnpmComponentDetectorFactory( public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Npm]; - public override int Version { get; } = 7; + public override int Version { get; } = 8; public override bool NeedsAutomaticRootDependencyCalculation => true;