From 1a6afdbf0154b3ea2f9082a762b2c559cdc88252 Mon Sep 17 00:00:00 2001 From: Aayush Maini Date: Tue, 10 Jun 2025 19:00:52 -0700 Subject: [PATCH 1/6] Process go process requests in order of depth --- .../go/GoComponentDetector.cs | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs index 685248bd1..3ddfca147 100644 --- a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs @@ -50,12 +50,12 @@ public GoComponentDetector( public override int Version => 9; - protected override Task> OnPrepareDetectionAsync( + protected async override Task> OnPrepareDetectionAsync( IObservable processRequests, IDictionary detectorArgs, CancellationToken cancellationToken = default) { - var goModProcessRequests = processRequests.Where(processRequest => + var filteredGoProcessRequests = await processRequests.Where(processRequest => { if (Path.GetFileName(processRequest.ComponentStream.Location) != "go.sum") { @@ -81,9 +81,15 @@ protected override Task> OnPrepareDetectionAsync( { goModFile?.Stream.Dispose(); } - }); + }).ToList(); // Materialize the filtered items for sorting - return Task.FromResult(goModProcessRequests); + // Sort by depth: shallow files (fewer directory segments) come first + var sortedGoProcessRequests = filteredGoProcessRequests + .OrderBy(pr => pr.ComponentStream.Location.Count(c => c == Path.DirectorySeparatorChar)) + .ThenBy(pr => Path.GetFileName(pr.ComponentStream.Location)) + .ToList(); + + return sortedGoProcessRequests.ToObservable(); } protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs, CancellationToken cancellationToken = default) @@ -108,7 +114,20 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID case ".MOD": { this.Logger.LogDebug("Found Go.mod: {Location}", file.Location); - await this.goParserFactory.CreateParser(GoParserType.GoMod, this.Logger).ParseAsync(singleFileComponentRecorder, file, record); + var wasModParsedSuccessfully = await this.goParserFactory.CreateParser(GoParserType.GoMod, this.Logger).ParseAsync(singleFileComponentRecorder, file, record); + + // Check if go.mod was parsed successfully and Go version is >= 1.17 in go.mod + if (wasModParsedSuccessfully && + !string.IsNullOrEmpty(record.GoModVersion) && + System.Version.TryParse(record.GoModVersion, out var goVersion) && + goVersion >= new Version(1, 17)) + { + this.projectRoots.Add(projectRootDirectory.FullName); + } + else + { + this.Logger.LogWarning("Not adding {Root} to processed roots: {ParseSuccess} {GoModVersion}", projectRootDirectory.FullName, wasModParsedSuccessfully, record.GoModVersion); + } if (await this.ShouldRunGoGraphAsync()) { From bf6b17b16631a9eea6a17e38b8a630b2fa330637 Mon Sep 17 00:00:00 2001 From: Aayush Maini Date: Tue, 10 Jun 2025 20:46:35 -0700 Subject: [PATCH 2/6] Add UTs to verify traversal order in go detector --- .../go/GoComponentDetector.cs | 2 +- .../GoComponentDetectorTests.cs | 213 ++++++++++++++++++ 2 files changed, 214 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs index 3ddfca147..750790405 100644 --- a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs @@ -86,7 +86,7 @@ protected async override Task> OnPrepareDetectionAsy // Sort by depth: shallow files (fewer directory segments) come first var sortedGoProcessRequests = filteredGoProcessRequests .OrderBy(pr => pr.ComponentStream.Location.Count(c => c == Path.DirectorySeparatorChar)) - .ThenBy(pr => Path.GetFileName(pr.ComponentStream.Location)) + .ThenBy(pr => pr.ComponentStream.Location) .ToList(); return sortedGoProcessRequests.ToObservable(); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs index 1c491e329..f7789cb4a 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs @@ -983,4 +983,217 @@ public async Task GoModDetector_VerifyLocalReferencesIgnored() .Should() .BeEquivalentTo(expectedComponentIds); } + + /// + /// Verify that nested directories are skipped once root is processed. + /// Assume root GoModVersion is >= 1.17. + /// + /// Task. + [TestMethod] + public async Task GoDetector_GoMod_VerifyNestedRootsUnderGTE117_AreSkipped() + { + var processedFiles = new List(); + this.SetupMockGoModParser(); + this.mockGoModParser + .Setup(p => p.ParseAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(true) + .Callback((_, file, record) => + { + processedFiles.Add(file.Location); + record.GoModVersion = "1.18"; + }); + + var (scanResult, componentRecorder) = await this.DetectorTestUtility + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .ExecuteDetectorAsync(); + + scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); + processedFiles.Should().ContainSingle(); + processedFiles.Should().OnlyContain(p => p == $@"C:\root\go.mod"); + } + + /// + /// Verify that nested roots under go mod less than 1.17 are not skipped. + /// + /// Task. + [TestMethod] + public async Task GoDetector_GoMod_VerifyNestedRootsUnderLT117AreNotSkipped() + { + var processedFiles = new List(); + this.SetupMockGoModParser(); + this.mockGoModParser + .Setup(p => p.ParseAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(true) + .Callback((_, file, record) => + { + processedFiles.Add(file.Location); + + record.GoModVersion = file.Location switch + { + @"C:\root\go.mod" => "1.16", + @"C:\root\a\go.mod" => "1.16", + @"C:\root\b\go.mod" => "1.17", + _ => null, + }; + }); + var (scanResult, componentRecorder) = await this.DetectorTestUtility + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .ExecuteDetectorAsync(); + + scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); + processedFiles.Should().HaveCount(5); + processedFiles.Should().ContainInOrder( + @"C:\root\go.mod", + @"C:\root\a\go.mod", + @"C:\root\b\go.mod", + @"C:\root\a\a\go.mod", + @"C:\root\a\b\go.mod"); + } + + /// + /// Verify that nested roots are not skipped if parent go.mod parsing fails. + /// + /// Task. + [TestMethod] + public async Task GoDetector_GoMod_VerifyNestedRootsAreNotSkippedIfParentParseFails() + { + var processedFiles = new List(); + this.SetupMockGoModParser(); + + this.mockGoModParser + .Setup(p => p.ParseAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync((ISingleFileComponentRecorder recorder, IComponentStream file, GoGraphTelemetryRecord record) => + { + processedFiles.Add(file.Location); + record.GoModVersion = file.Location switch + { + @"C:\root\b\go.mod" => "1.18", + _ => "1.16", + }; + + // Simulate parse failure only for C:\root\a\go.mod + if (file.Location == @"C:\root\a\go.mod") + { + return false; + } + + return true; + }); + + var (scanResult, componentRecorder) = await this.DetectorTestUtility + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .ExecuteDetectorAsync(); + + scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); + processedFiles.Should().HaveCount(5); + processedFiles.Should().ContainInOrder( + @"C:\root\go.mod", + @"C:\root\a\go.mod", + @"C:\root\b\go.mod", + @"C:\root\a\a\go.mod", + @"C:\root\a\b\go.mod"); + } + + /// + /// Verify that nested directories are skipped once root is processed. + /// Assume root GoModVersion is >= 1.17. + /// + /// Task. + [TestMethod] + public async Task GoDetector_GoSum_VerifyNestedRootsUnderGoSum_AreSkipped() + { + var processedFiles = new List(); + this.envVarService.Setup(x => x.IsEnvironmentVariableValueTrue("DisableGoCliScan")).Returns(false); + this.SetupMockGoCLIParser(); + this.mockGoCliParser + .Setup(p => p.ParseAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(true) + .Callback((_, file, record) => + { + processedFiles.Add(file.Location); + }); + + var (scanResult, componentRecorder) = await this.DetectorTestUtility + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") + .WithFile("go.sum", string.Empty, fileLocation: @"C:\root\go.sum") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .ExecuteDetectorAsync(); + + scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); + processedFiles.Should().ContainSingle(); + processedFiles.Should().OnlyContain(p => p == $@"C:\root\go.sum"); + } + + [TestMethod] + public async Task GoDetector_GoSum_VerifyNestedRootsAreNotSkippedIfParentParseFails() + { + var processedFiles = new List(); + this.envVarService.Setup(x => x.IsEnvironmentVariableValueTrue("DisableGoCliScan")).Returns(false); + this.SetupMockGoModParser(); + this.SetupMockGoCLIParser(); + this.SetupMockGoSumParser(); + + this.mockGoModParser + .Setup(p => p.ParseAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync((ISingleFileComponentRecorder recorder, IComponentStream file, GoGraphTelemetryRecord record) => + { + processedFiles.Add(file.Location); + record.GoModVersion = file.Location switch + { + @"C:\root\b\go.mod" => "1.18", + _ => "1.16", + }; + + return true; + }); + + this.mockGoCliParser + .Setup(p => p.ParseAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync((ISingleFileComponentRecorder recorder, IComponentStream file, GoGraphTelemetryRecord record) => + { + processedFiles.Add(file.Location); + return file.Location != @"C:\root\a\go.sum"; + }); + + var (scanResult, componentRecorder) = await this.DetectorTestUtility + .WithFile("go.sum", string.Empty, fileLocation: @"C:\root\a\go.sum") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .ExecuteDetectorAsync(); + + scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); + processedFiles.Should().HaveCount(5); + processedFiles.Should().ContainInOrder( + @"C:\root\go.mod", + @"C:\root\a\go.sum", + @"C:\root\b\go.mod", + @"C:\root\a\a\go.mod", + @"C:\root\a\b\go.mod"); + } } From 9dcd9e806725892e082861109a5bb5833a70a2c5 Mon Sep 17 00:00:00 2001 From: Aayush Maini Date: Tue, 10 Jun 2025 21:25:31 -0700 Subject: [PATCH 3/6] Fix paths for cross-plat UTs --- .../GoComponentDetectorTests.cs | 121 ++++++++++-------- 1 file changed, 66 insertions(+), 55 deletions(-) diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs index f7789cb4a..e3a9ccd6a 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs @@ -1003,19 +1003,20 @@ public async Task GoDetector_GoMod_VerifyNestedRootsUnderGTE117_AreSkipped() record.GoModVersion = "1.18"; }); + var root = Path.Combine("C:", "root"); var (scanResult, componentRecorder) = await this.DetectorTestUtility - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "a", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "b", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "d", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "a", "go.mod")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); processedFiles.Should().ContainSingle(); - processedFiles.Should().OnlyContain(p => p == $@"C:\root\go.mod"); + processedFiles.Should().OnlyContain(p => p == Path.Combine(root, "go.mod")); } /// @@ -1025,6 +1026,7 @@ public async Task GoDetector_GoMod_VerifyNestedRootsUnderGTE117_AreSkipped() [TestMethod] public async Task GoDetector_GoMod_VerifyNestedRootsUnderLT117AreNotSkipped() { + var root = Path.Combine("C:", "root"); var processedFiles = new List(); this.SetupMockGoModParser(); this.mockGoModParser @@ -1033,23 +1035,26 @@ public async Task GoDetector_GoMod_VerifyNestedRootsUnderLT117AreNotSkipped() .Callback((_, file, record) => { processedFiles.Add(file.Location); - + var rootMod = Path.Combine(root, "go.mod"); + var aMod = Path.Combine(root, "a", "go.mod"); + var bMod = Path.Combine(root, "b", "go.mod"); record.GoModVersion = file.Location switch { - @"C:\root\go.mod" => "1.16", - @"C:\root\a\go.mod" => "1.16", - @"C:\root\b\go.mod" => "1.17", + var loc when loc == rootMod => "1.16", + var loc when loc == aMod => "1.16", + var loc when loc == bMod => "1.17", _ => null, }; }); + var (scanResult, componentRecorder) = await this.DetectorTestUtility - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "a", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "b", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "d", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "a", "go.mod")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -1070,6 +1075,7 @@ public async Task GoDetector_GoMod_VerifyNestedRootsUnderLT117AreNotSkipped() public async Task GoDetector_GoMod_VerifyNestedRootsAreNotSkippedIfParentParseFails() { var processedFiles = new List(); + var root = Path.Combine("C:", "root"); this.SetupMockGoModParser(); this.mockGoModParser @@ -1077,14 +1083,16 @@ public async Task GoDetector_GoMod_VerifyNestedRootsAreNotSkippedIfParentParseFa .ReturnsAsync((ISingleFileComponentRecorder recorder, IComponentStream file, GoGraphTelemetryRecord record) => { processedFiles.Add(file.Location); + var aMod = Path.Combine(root, "a", "go.mod"); + var bMod = Path.Combine(root, "b", "go.mod"); record.GoModVersion = file.Location switch { - @"C:\root\b\go.mod" => "1.18", + var loc when loc == bMod => "1.18", _ => "1.16", }; // Simulate parse failure only for C:\root\a\go.mod - if (file.Location == @"C:\root\a\go.mod") + if (file.Location == aMod) { return false; } @@ -1093,23 +1101,23 @@ public async Task GoDetector_GoMod_VerifyNestedRootsAreNotSkippedIfParentParseFa }); var (scanResult, componentRecorder) = await this.DetectorTestUtility - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "a", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "b", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "d", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "a", "go.mod")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); processedFiles.Should().HaveCount(5); processedFiles.Should().ContainInOrder( - @"C:\root\go.mod", - @"C:\root\a\go.mod", - @"C:\root\b\go.mod", - @"C:\root\a\a\go.mod", - @"C:\root\a\b\go.mod"); + Path.Combine(root, "go.mod"), + Path.Combine(root, "a", "go.mod"), + Path.Combine(root, "b", "go.mod"), + Path.Combine(root, "a", "a", "go.mod"), + Path.Combine(root, "a", "b", "go.mod")); } /// @@ -1121,6 +1129,7 @@ public async Task GoDetector_GoMod_VerifyNestedRootsAreNotSkippedIfParentParseFa public async Task GoDetector_GoSum_VerifyNestedRootsUnderGoSum_AreSkipped() { var processedFiles = new List(); + var root = Path.Combine("C:", "root"); this.envVarService.Setup(x => x.IsEnvironmentVariableValueTrue("DisableGoCliScan")).Returns(false); this.SetupMockGoCLIParser(); this.mockGoCliParser @@ -1132,24 +1141,25 @@ public async Task GoDetector_GoSum_VerifyNestedRootsUnderGoSum_AreSkipped() }); var (scanResult, componentRecorder) = await this.DetectorTestUtility - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") - .WithFile("go.sum", string.Empty, fileLocation: @"C:\root\go.sum") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "a", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "b", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "go.mod")) + .WithFile("go.sum", string.Empty, fileLocation: Path.Combine(root, "go.sum")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "d", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "a", "go.mod")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); processedFiles.Should().ContainSingle(); - processedFiles.Should().OnlyContain(p => p == $@"C:\root\go.sum"); + processedFiles.Should().OnlyContain(p => p == Path.Combine(root, "go.sum")); } [TestMethod] public async Task GoDetector_GoSum_VerifyNestedRootsAreNotSkippedIfParentParseFails() { var processedFiles = new List(); + var root = Path.Combine("C:", "root"); this.envVarService.Setup(x => x.IsEnvironmentVariableValueTrue("DisableGoCliScan")).Returns(false); this.SetupMockGoModParser(); this.SetupMockGoCLIParser(); @@ -1160,9 +1170,10 @@ public async Task GoDetector_GoSum_VerifyNestedRootsAreNotSkippedIfParentParseFa .ReturnsAsync((ISingleFileComponentRecorder recorder, IComponentStream file, GoGraphTelemetryRecord record) => { processedFiles.Add(file.Location); + var bMod = Path.Combine(root, "b", "go.mod"); record.GoModVersion = file.Location switch { - @"C:\root\b\go.mod" => "1.18", + var loc when loc == bMod => "1.18", _ => "1.16", }; @@ -1174,26 +1185,26 @@ public async Task GoDetector_GoSum_VerifyNestedRootsAreNotSkippedIfParentParseFa .ReturnsAsync((ISingleFileComponentRecorder recorder, IComponentStream file, GoGraphTelemetryRecord record) => { processedFiles.Add(file.Location); - return file.Location != @"C:\root\a\go.sum"; + return file.Location != Path.Combine(root, "a", "go.sum"); }); var (scanResult, componentRecorder) = await this.DetectorTestUtility - .WithFile("go.sum", string.Empty, fileLocation: @"C:\root\a\go.sum") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\a\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\a\b\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\d\go.mod") - .WithFile("go.mod", string.Empty, fileLocation: @"C:\root\b\a\go.mod") + .WithFile("go.sum", string.Empty, fileLocation: Path.Combine(root, "a", "go.sum")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "a", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "a", "b", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "d", "go.mod")) + .WithFile("go.mod", string.Empty, fileLocation: Path.Combine(root, "b", "a", "go.mod")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); processedFiles.Should().HaveCount(5); processedFiles.Should().ContainInOrder( - @"C:\root\go.mod", - @"C:\root\a\go.sum", - @"C:\root\b\go.mod", - @"C:\root\a\a\go.mod", - @"C:\root\a\b\go.mod"); + Path.Combine(root, "go.mod"), + Path.Combine(root, "a", "go.sum"), + Path.Combine(root, "b", "go.mod"), + Path.Combine(root, "a", "a", "go.mod"), + Path.Combine(root, "a", "b", "go.mod")); } } From 1a827d2ac361f2676d53e23b37f514a577cca8b7 Mon Sep 17 00:00:00 2001 From: Aayush Maini Date: Tue, 10 Jun 2025 21:29:39 -0700 Subject: [PATCH 4/6] Fix another path in UT --- .../GoComponentDetectorTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs index e3a9ccd6a..eec1a69b6 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs @@ -1060,11 +1060,11 @@ public async Task GoDetector_GoMod_VerifyNestedRootsUnderLT117AreNotSkipped() scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); processedFiles.Should().HaveCount(5); processedFiles.Should().ContainInOrder( - @"C:\root\go.mod", - @"C:\root\a\go.mod", - @"C:\root\b\go.mod", - @"C:\root\a\a\go.mod", - @"C:\root\a\b\go.mod"); + Path.Combine(root, "go.mod"), + Path.Combine(root, "a", "go.mod"), + Path.Combine(root, "b", "go.mod"), + Path.Combine(root, "a", "a", "go.mod"), + Path.Combine(root, "a", "b", "go.mod")); } /// From f6104bd8b374209fa1b517f0020b50d8fbfdb5f3 Mon Sep 17 00:00:00 2001 From: Aayush Maini Date: Wed, 11 Jun 2025 01:16:15 -0700 Subject: [PATCH 5/6] CR: Change level of a noisy trace --- .../go/GoComponentDetector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs index 750790405..398a1fa44 100644 --- a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs @@ -126,7 +126,7 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID } else { - this.Logger.LogWarning("Not adding {Root} to processed roots: {ParseSuccess} {GoModVersion}", projectRootDirectory.FullName, wasModParsedSuccessfully, record.GoModVersion); + this.Logger.LogDebug("Not adding {Root} to processed roots: {ParseSuccess} {GoModVersion}", projectRootDirectory.FullName, wasModParsedSuccessfully, record.GoModVersion); } if (await this.ShouldRunGoGraphAsync()) From fc46c8f20d2b7fecf3f80b8d556747b85a0189ad Mon Sep 17 00:00:00 2001 From: Aayush Maini Date: Wed, 11 Jun 2025 01:18:19 -0700 Subject: [PATCH 6/6] Bump detector version --- .../go/GoComponentDetector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs index 398a1fa44..6451738bb 100644 --- a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs @@ -48,7 +48,7 @@ public GoComponentDetector( public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Go]; - public override int Version => 9; + public override int Version => 10; protected async override Task> OnPrepareDetectionAsync( IObservable processRequests,