From 282751a980feb390285506f6160d90a67beb4dda Mon Sep 17 00:00:00 2001 From: Gregory Paidis Date: Tue, 9 Jul 2024 15:44:59 +0200 Subject: [PATCH] Add support for JRE provisioning: Jre tar.gz unpack --- NuGet.Config | 3 +- .../JreCaching/JreCacheTests.cs | 24 ++-- .../JreCaching/TarGzUnpackTests.cs | 110 ++++++++++++++++++ .../JreCaching/UnpackerFactoryTests.cs | 15 ++- .../JreCaching/IUnpackerFactory.cs | 2 +- .../JreCaching/JreCache.cs | 10 +- .../JreCaching/TarGzUnpacker.cs | 95 +++++++++++++++ .../JreCaching/UnpackerFactory.cs | 6 +- .../PreprocessorObjectFactory.cs | 8 +- .../SonarScanner.MSBuild.PreProcessor.csproj | 2 + 10 files changed, 250 insertions(+), 25 deletions(-) create mode 100644 Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/TarGzUnpackTests.cs create mode 100644 src/SonarScanner.MSBuild.PreProcessor/JreCaching/TarGzUnpacker.cs diff --git a/NuGet.Config b/NuGet.Config index 5f80eb3dd..9110ed897 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -32,7 +32,8 @@ - Microsoft;sharwell;meirb;dotnetfoundation;castleproject;jonorossi;onovotny;fluentassertions;jamesnk;CycloneDX;grpc-packages;protobuf-packages;NSubstitute;kzu + + Microsoft;sharwell;meirb;dotnetfoundation;castleproject;jonorossi;onovotny;fluentassertions;jamesnk;CycloneDX;grpc-packages;protobuf-packages;NSubstitute;kzu;SharpDevelop diff --git a/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/JreCacheTests.cs b/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/JreCacheTests.cs index 20388de67..dd5a07cd7 100644 --- a/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/JreCacheTests.cs +++ b/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/JreCacheTests.cs @@ -44,6 +44,7 @@ public class JreCacheTests private readonly IChecksum checksum; private readonly IUnpacker unpacker; private readonly IUnpackerFactory unpackerFactory; + private readonly IOperatingSystemProvider operatingSystemProvider; // https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.createdirectory // https://learn.microsoft.com/en-us/dotnet/api/system.io.file.create @@ -70,7 +71,8 @@ public JreCacheTests() checksum = Substitute.For(); unpacker = Substitute.For(); unpackerFactory = Substitute.For(); - unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, TestArchiveName).Returns(unpacker); + operatingSystemProvider = Substitute.For(); + unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, operatingSystemProvider, TestArchiveName).Returns(unpacker); } [TestMethod] @@ -233,7 +235,7 @@ public async Task Download_DownloadFileNew_Success_WithTestFiles() var fileWrapperIO = FileWrapper.Instance; var downloadContentArray = new byte[] { 1, 2, 3 }; - var sut = new JreCache(testLogger, directoryWrapperIO, fileWrapperIO, checksum, unpackerFactory); + var sut = new JreCache(testLogger, directoryWrapperIO, fileWrapperIO, checksum, unpackerFactory, operatingSystemProvider); try { var result = await sut.DownloadJreAsync(home, new(TestArchiveName, sha, "javaPath"), () => Task.FromResult(new MemoryStream(downloadContentArray))); @@ -265,7 +267,7 @@ public async Task Download_DownloadFileNew_Failure_WithTestFiles() var directoryWrapperIO = DirectoryWrapper.Instance; // Do real I/O operations in this test and only fake the download. var fileWrapperIO = FileWrapper.Instance; - var sut = new JreCache(testLogger, directoryWrapperIO, fileWrapperIO, checksum, unpackerFactory); + var sut = new JreCache(testLogger, directoryWrapperIO, fileWrapperIO, checksum, unpackerFactory, operatingSystemProvider); try { var result = await sut.DownloadJreAsync(home, new(TestArchiveName, sha, "javaPath"), () => throw new InvalidOperationException("Download failure simulation.")); @@ -565,7 +567,7 @@ public async Task UnpackerFactory_Success() fileWrapper.Exists(file).Returns(false); fileWrapper.Create(Arg.Any()).Returns(new MemoryStream()); checksum.ComputeHash(Arg.Any()).Returns("sha256"); - unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, TestArchiveName).Returns(Substitute.For()); + unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, operatingSystemProvider, TestArchiveName).Returns(Substitute.For()); var sut = CreateSutWithSubstitutes(); var result = await sut.DownloadJreAsync(home, new(TestArchiveName, "sha256", "javaPath"), () => Task.FromResult(new MemoryStream())); @@ -574,7 +576,7 @@ public async Task UnpackerFactory_Success() fileWrapper.Received(1).Create(Arg.Any()); fileWrapper.Received(2).Open(file); // One for the checksum and the other for the unpacking. checksum.Received(1).ComputeHash(Arg.Any()); - unpackerFactory.Received(1).CreateForArchive(directoryWrapper, fileWrapper, TestArchiveName); + unpackerFactory.Received(1).CreateForArchive(directoryWrapper, fileWrapper, operatingSystemProvider, TestArchiveName); testLogger.DebugMessages.Should().SatisfyRespectively( x => x.Should().Be(@"Starting the Java Runtime Environment download."), x => x.Should().Be(@"The checksum of the downloaded file is 'sha256' and the expected checksum is 'sha256'."), @@ -591,7 +593,7 @@ public async Task UnpackerFactory_ReturnsNull() var sha = Path.Combine(cache, "sha256"); directoryWrapper.Exists(cache).Returns(true); directoryWrapper.Exists(sha).Returns(true); - unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, TestArchiveName).ReturnsNull(); + unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, operatingSystemProvider, TestArchiveName).ReturnsNull(); var sut = CreateSutWithSubstitutes(); var result = await sut.DownloadJreAsync(home, new(TestArchiveName, "sha256", "javaPath"), () => Task.FromResult(new MemoryStream())); @@ -600,7 +602,7 @@ public async Task UnpackerFactory_ReturnsNull() fileWrapper.DidNotReceiveWithAnyArgs().Create(null); fileWrapper.DidNotReceiveWithAnyArgs().Open(null); checksum.DidNotReceiveWithAnyArgs().ComputeHash(null); - unpackerFactory.Received(1).CreateForArchive(directoryWrapper, fileWrapper, TestArchiveName); + unpackerFactory.Received(1).CreateForArchive(directoryWrapper, fileWrapper, operatingSystemProvider, TestArchiveName); testLogger.DebugMessages.Should().BeEmpty(); } @@ -612,7 +614,7 @@ public async Task UnpackerFactory_Throws() var sha = Path.Combine(cache, "sha256"); directoryWrapper.Exists(cache).Returns(true); directoryWrapper.Exists(sha).Returns(true); - unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, TestArchiveName).ReturnsNull(); + unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, operatingSystemProvider, TestArchiveName).ReturnsNull(); var sut = CreateSutWithSubstitutes(); var result = await sut.DownloadJreAsync(home, new(TestArchiveName, "sha256", "javaPath"), () => Task.FromResult(new MemoryStream())); @@ -621,7 +623,7 @@ public async Task UnpackerFactory_Throws() fileWrapper.DidNotReceiveWithAnyArgs().Create(null); fileWrapper.DidNotReceiveWithAnyArgs().Open(null); checksum.DidNotReceiveWithAnyArgs().ComputeHash(null); - unpackerFactory.Received(1).CreateForArchive(directoryWrapper, fileWrapper, TestArchiveName); + unpackerFactory.Received(1).CreateForArchive(directoryWrapper, fileWrapper, operatingSystemProvider, TestArchiveName); } [TestMethod] @@ -814,7 +816,7 @@ public async Task EndToEndTestWithFiles_Success() var realFileWrapper = FileWrapper.Instance; var realChecksum = new ChecksumSha256(); var realUnpackerFactory = new UnpackerFactory(); - var sut = new JreCache(testLogger, realDirectoryWrapper, realFileWrapper, realChecksum, realUnpackerFactory); + var sut = new JreCache(testLogger, realDirectoryWrapper, realFileWrapper, realChecksum, realUnpackerFactory, operatingSystemProvider); try { var result = await sut.DownloadJreAsync(home, jreDescriptor, () => Task.FromResult(new MemoryStream(zipContent))); @@ -843,5 +845,5 @@ public async Task EndToEndTestWithFiles_Success() } private JreCache CreateSutWithSubstitutes() => - new JreCache(testLogger, directoryWrapper, fileWrapper, checksum, unpackerFactory); + new JreCache(testLogger, directoryWrapper, fileWrapper, checksum, unpackerFactory, operatingSystemProvider); } diff --git a/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/TarGzUnpackTests.cs b/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/TarGzUnpackTests.cs new file mode 100644 index 000000000..1944026ed --- /dev/null +++ b/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/TarGzUnpackTests.cs @@ -0,0 +1,110 @@ +/* + * SonarScanner for .NET + * Copyright (C) 2016-2024 SonarSource SA + * mailto: info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using System; +using System.IO; +using FluentAssertions; +using ICSharpCode.SharpZipLib.Core; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using NSubstitute; +using SonarScanner.MSBuild.Common; +using SonarScanner.MSBuild.PreProcessor.JreCaching; +using TestUtilities; + +namespace SonarScanner.MSBuild.PreProcessor.Test.JreCaching; + +[TestClass] +public class TarGzUnpackTests +{ + [TestMethod] + public void TarGzUnpacking_Success() + { + // A sample zip file with the following content: + // Main + // ├── Sub + // └── Sub2 + // └── Sample.txt + const string sampleTarGzFile = """ + H4sICL04jWYEAE1haW4udGFyAO3SUQrDIAyA4RzFE2wao55iTz2BBccK3Ribw + nb7iVDKnkqh+mK+l4S8/rn46XGGumTmnMuz+JvLrsiSRk1ImO/WkgRhoIH0jv + 4lBHSq9B/SWPMHdvVHk+9OO+T+LSz9seID7OpPpT8Zy/1bWPsP/v6cwyl+Ihx + ss78ya3+T70qR1iAkNNB5/1v4ijH4FKdrmoExxlgvfmqGu7oADgAA + """; + var baseDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + var main = Path.Combine(baseDirectory, "Main"); + var sub1 = Path.Combine(baseDirectory, "Main", "Sub"); + var sub2 = Path.Combine(baseDirectory, "Main", "Sub2"); + var sampleTxt = Path.Combine(baseDirectory, "Main", "Sub2", "Sample.txt"); + var osProvider = Substitute.For(); + osProvider.OperatingSystem().Returns(PlatformOS.MacOSX); + using var archive = new MemoryStream(Convert.FromBase64String(sampleTarGzFile)); + var sut = new TarGzUnpacker(DirectoryWrapper.Instance, FileWrapper.Instance, osProvider); + try + { + sut.Unpack(archive, baseDirectory); + + Directory.Exists(main).Should().BeTrue(); + Directory.Exists(sub1).Should().BeTrue(); + Directory.Exists(sub2).Should().BeTrue(); + File.Exists(sampleTxt).Should().BeTrue(); + var content = File.ReadAllText(sampleTxt).NormalizeLineEndings(); + content.Should().Be("hey beautiful"); + } + finally + { + Directory.Delete(baseDirectory, true); + } + } + + [TestMethod] + public void TarGzUnpacking_Fails_InvalidZipFile() + { + var baseDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + using var archive = new MemoryStream([1, 2, 3]); // Invalid archive content + var sut = new TarGzUnpacker(DirectoryWrapper.Instance, FileWrapper.Instance, Substitute.For()); + + var action = () => sut.Unpack(archive, baseDirectory); + + action.Should().Throw().WithMessage("Error GZIP header, first magic byte doesn't match"); + Directory.Exists(baseDirectory).Should().BeFalse(); + } + + [TestMethod] + public void TarGzUnpacking_ZipSlip_IsDetected() + { + // zip-slip.zip from https://github.com/kevva/decompress/issues/71 + // google "Zip Slip Vulnerability" for details + const string zipSlip = """ + H4sICJDill0C/215LXNsaXAudGFyAO3TvQrCMBSG4cxeRa4gTdKk + XRUULHQo2MlNUET8K7aC9OrFFsTFn0ELlffhwDmcZEngU4EKhunx + sE43h634Dd161rWL3X1u9sZYa4VMRQfOZbU4Sfn1R/aEUgH1YVX7 + Iih3m6JYLVV1qcQ/6OLnbnmIoibjJvb6sbesESb0znsfGh8Kba1z + XkjdZf6Pdb1bvbj37ryn+Z8nmcyno1zO0iTLJuOBAAAAAAAAAAAA + AAAAQJ9cAZCup/MAKAAA + """; + var baseDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + using var zipStream = new MemoryStream(Convert.FromBase64String(zipSlip)); + var sut = new TarGzUnpacker(DirectoryWrapper.Instance, FileWrapper.Instance, Substitute.For()); + + var action = () => sut.Unpack(zipStream, baseDirectory); + + action.Should().Throw().WithMessage("Parent traversal in paths is not allowed"); + } +} diff --git a/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/UnpackerFactoryTests.cs b/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/UnpackerFactoryTests.cs index 2fcb359ac..7a11fdb62 100644 --- a/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/UnpackerFactoryTests.cs +++ b/Tests/SonarScanner.MSBuild.PreProcessor.Test/JreCaching/UnpackerFactoryTests.cs @@ -35,23 +35,28 @@ public class UnpackerFactoryTests [DataRow("File.ZIP", typeof(ZipUnpacker))] [DataRow(@"c:\test\File.ZIP", typeof(ZipUnpacker))] [DataRow(@"/usr/File.zip", typeof(ZipUnpacker))] + [DataRow("File.tar.gz", typeof(TarGzUnpacker))] + [DataRow("File.TAR.GZ", typeof(TarGzUnpacker))] + [DataRow(@"c:\test\File.GZ", typeof(TarGzUnpacker))] + [DataRow(@"/usr/File.TAR.gz", typeof(TarGzUnpacker))] public void SupportedFileExtensions(string fileName, Type expectedUnpacker) { var sut = new UnpackerFactory(); - var unpacker = sut.CreateForArchive(Substitute.For(), Substitute.For(), fileName); + + var unpacker = sut.CreateForArchive(Substitute.For(), Substitute.For(), Substitute.For(), fileName); + unpacker.Should().BeOfType(expectedUnpacker); } [DataTestMethod] - [DataRow("File.tar")] - [DataRow("File.tar.gz")] - [DataRow("File.gz")] [DataRow("File.rar")] [DataRow("File.7z")] public void UnsupportedFileExtensions(string fileName) { var sut = new UnpackerFactory(); - var unpacker = sut.CreateForArchive(Substitute.For(), Substitute.For(), fileName); + + var unpacker = sut.CreateForArchive(Substitute.For(), Substitute.For(), Substitute.For(), fileName); + unpacker.Should().BeNull(); } } diff --git a/src/SonarScanner.MSBuild.PreProcessor/JreCaching/IUnpackerFactory.cs b/src/SonarScanner.MSBuild.PreProcessor/JreCaching/IUnpackerFactory.cs index f65864fb4..82ef94db6 100644 --- a/src/SonarScanner.MSBuild.PreProcessor/JreCaching/IUnpackerFactory.cs +++ b/src/SonarScanner.MSBuild.PreProcessor/JreCaching/IUnpackerFactory.cs @@ -24,5 +24,5 @@ namespace SonarScanner.MSBuild.PreProcessor.JreCaching; public interface IUnpackerFactory { - IUnpacker CreateForArchive(IDirectoryWrapper directoryWrapper, IFileWrapper fileWrapper, string archive); + IUnpacker CreateForArchive(IDirectoryWrapper directoryWrapper, IFileWrapper fileWrapper, IOperatingSystemProvider operatingSystemProvider, string archive); } diff --git a/src/SonarScanner.MSBuild.PreProcessor/JreCaching/JreCache.cs b/src/SonarScanner.MSBuild.PreProcessor/JreCaching/JreCache.cs index dc45982fe..cb8bb52a1 100644 --- a/src/SonarScanner.MSBuild.PreProcessor/JreCaching/JreCache.cs +++ b/src/SonarScanner.MSBuild.PreProcessor/JreCaching/JreCache.cs @@ -25,7 +25,13 @@ namespace SonarScanner.MSBuild.PreProcessor.JreCaching; -internal class JreCache(ILogger logger, IDirectoryWrapper directoryWrapper, IFileWrapper fileWrapper, IChecksum checksum, IUnpackerFactory unpackerFactory) : IJreCache +internal class JreCache( + ILogger logger, + IDirectoryWrapper directoryWrapper, + IFileWrapper fileWrapper, + IChecksum checksum, + IUnpackerFactory unpackerFactory, + IOperatingSystemProvider operatingSystemProvider) : IJreCache { public JreCacheResult IsJreCached(string sonarUserHome, JreDescriptor jreDescriptor) { @@ -55,7 +61,7 @@ public async Task DownloadJreAsync(string sonarUserHome, JreDesc return new JreCacheFailure(string.Format(Resources.ERR_CacheDirectoryCouldNotBeCreated, JreRootPath(jreDescriptor, JresCacheRoot(sonarUserHome)))); } // If we do not support the archive format, there is no point in downloading. Therefore we bail out early in such a case. - if (unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, jreDescriptor.Filename) is not { } unpacker) + if (unpackerFactory.CreateForArchive(directoryWrapper, fileWrapper, operatingSystemProvider, jreDescriptor.Filename) is not { } unpacker) { return new JreCacheFailure(string.Format(Resources.ERR_JreArchiveFormatNotSupported, jreDescriptor.Filename)); } diff --git a/src/SonarScanner.MSBuild.PreProcessor/JreCaching/TarGzUnpacker.cs b/src/SonarScanner.MSBuild.PreProcessor/JreCaching/TarGzUnpacker.cs new file mode 100644 index 000000000..7475b2b45 --- /dev/null +++ b/src/SonarScanner.MSBuild.PreProcessor/JreCaching/TarGzUnpacker.cs @@ -0,0 +1,95 @@ +/* + * SonarScanner for .NET + * Copyright (C) 2016-2024 SonarSource SA + * mailto: info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using System; +using System.IO; +using ICSharpCode.SharpZipLib.Core; +using ICSharpCode.SharpZipLib.GZip; +using ICSharpCode.SharpZipLib.Tar; +using SonarScanner.MSBuild.Common; + +namespace SonarScanner.MSBuild.PreProcessor.JreCaching; + +public class TarGzUnpacker(IDirectoryWrapper directoryWrapper, IFileWrapper fileWrapper, IOperatingSystemProvider operatingSystemProvider) : IUnpacker +{ + // ref https://github.com/icsharpcode/SharpZipLib/blob/ff2d7c30bdb2474d507f001bc555405e9f02a0bb/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs#L608 + public void Unpack(Stream archive, string destinationDirectory) + { + using var gzipStream = new GZipInputStream(archive); + using var tarIn = new TarInputStream(gzipStream, null); + + var destinationFullPath = Path.GetFullPath(destinationDirectory).TrimEnd('/', '\\'); + while (tarIn.GetNextEntry() is {} entry) + { + if (entry.TarHeader.TypeFlag is not TarHeader.LF_LINK or TarHeader.LF_SYMLINK) + { + ExtractEntry(tarIn, destinationFullPath, entry); + } + } + } + + // ref https://github.com/icsharpcode/SharpZipLib/blob/ff2d7c30bdb2474d507f001bc555405e9f02a0bb/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs#L644 + private void ExtractEntry(TarInputStream tar, string destinationFullPath, TarEntry entry) + { + var name = entry.Name; + + if (Path.IsPathRooted(name)) + { + // NOTE: + // for UNC names... \\machine\share\zoom\beet.txt gives \zoom\beet.txt + name = name.Substring(Path.GetPathRoot(name).Length); + } + + name = name.Replace('/', Path.DirectorySeparatorChar); + + var destinationFile = Path.Combine(destinationFullPath, name); + var destinationFileDirectory = Path.GetDirectoryName(Path.GetFullPath(destinationFile)) ?? string.Empty; + + var isRootDir = entry.IsDirectory && entry.Name == string.Empty; + + if (!isRootDir && !destinationFileDirectory.StartsWith(destinationFullPath, StringComparison.InvariantCultureIgnoreCase)) + { + throw new InvalidNameException("Parent traversal in paths is not allowed"); + } + + if (entry.IsDirectory) + { + directoryWrapper.CreateDirectory(destinationFile); + } + else + { + directoryWrapper.CreateDirectory(destinationFileDirectory); + + using var outputStream = fileWrapper.Create(destinationFile); + // If translation is disabled, just copy the entry across directly. + tar.CopyEntryContents(outputStream); + +#if NETSTANDARD + if (operatingSystemProvider.OperatingSystem() is PlatformOS.Linux or PlatformOS.Alpine) + { + _ = new Mono.Unix.UnixFileInfo(destinationFile) + { + FileAccessPermissions = (Mono.Unix.FileAccessPermissions)entry.TarHeader.Mode // set the same permissions as inside the archive + }; + } +#endif + } + } +} diff --git a/src/SonarScanner.MSBuild.PreProcessor/JreCaching/UnpackerFactory.cs b/src/SonarScanner.MSBuild.PreProcessor/JreCaching/UnpackerFactory.cs index 4489be189..c41151967 100644 --- a/src/SonarScanner.MSBuild.PreProcessor/JreCaching/UnpackerFactory.cs +++ b/src/SonarScanner.MSBuild.PreProcessor/JreCaching/UnpackerFactory.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using System; using System.IO; using SonarScanner.MSBuild.Common; @@ -28,10 +27,11 @@ public class UnpackerFactory : IUnpackerFactory { public static UnpackerFactory Instance { get; } = new UnpackerFactory(); - public IUnpacker CreateForArchive(IDirectoryWrapper directoryWrapper, IFileWrapper fileWrapper, string archive) => + public IUnpacker CreateForArchive(IDirectoryWrapper directoryWrapper, IFileWrapper fileWrapper, IOperatingSystemProvider operatingSystemProvider, string archive) => Path.GetExtension(archive).ToUpperInvariant() switch { ".ZIP" => new ZipUnpacker(), - _ => null, + ".GZ" => new TarGzUnpacker(directoryWrapper, fileWrapper, operatingSystemProvider), + _ => null }; } diff --git a/src/SonarScanner.MSBuild.PreProcessor/PreprocessorObjectFactory.cs b/src/SonarScanner.MSBuild.PreProcessor/PreprocessorObjectFactory.cs index d8bc88117..dd1d71152 100644 --- a/src/SonarScanner.MSBuild.PreProcessor/PreprocessorObjectFactory.cs +++ b/src/SonarScanner.MSBuild.PreProcessor/PreprocessorObjectFactory.cs @@ -87,8 +87,12 @@ public IAnalyzerProvider CreateRoslynAnalyzerProvider(ISonarWebServer server, st return new RoslynAnalyzerProvider(new EmbeddedAnalyzerInstaller(server, localCacheTempPath, logger), logger); } - public IJreResolver CreateJreResolver(ISonarWebServer server) => - new JreResolver(server, new JreCache(logger, DirectoryWrapper.Instance, FileWrapper.Instance, ChecksumSha256.Instance, UnpackerFactory.Instance), logger); + public IJreResolver CreateJreResolver(ISonarWebServer server) + { + var osProvider = new OperatingSystemProvider(FileWrapper.Instance, logger); + var cache = new JreCache(logger, DirectoryWrapper.Instance, FileWrapper.Instance, ChecksumSha256.Instance, UnpackerFactory.Instance, osProvider); + return new JreResolver(server, cache, logger); + } private bool ValidateServerUrl(string serverUrl) { diff --git a/src/SonarScanner.MSBuild.PreProcessor/SonarScanner.MSBuild.PreProcessor.csproj b/src/SonarScanner.MSBuild.PreProcessor/SonarScanner.MSBuild.PreProcessor.csproj index 0371093e1..158949eb1 100644 --- a/src/SonarScanner.MSBuild.PreProcessor/SonarScanner.MSBuild.PreProcessor.csproj +++ b/src/SonarScanner.MSBuild.PreProcessor/SonarScanner.MSBuild.PreProcessor.csproj @@ -18,7 +18,9 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + +