From d50f65e602575de93d34106dadd8faf8ecf6bf3d Mon Sep 17 00:00:00 2001 From: Asaf Agami Date: Wed, 24 Aug 2022 16:50:34 +0300 Subject: [PATCH] [ROAD-1111] Encryption error workaround (#207) --- CHANGELOG.md | 3 ++ Snyk.Code.Library/Api/Encoding/Encoder.cs | 31 ++++++++++++++----- Snyk.Code.Library/Api/SnykCodeClient.cs | 9 ++++-- Snyk.Code.Library/Service/AnalysisService.cs | 2 +- Snyk.Code.Library/Service/BundleService.cs | 21 ++++++++----- .../Service/SnykTasksService.cs | 8 ++--- .../VsStatusBarNotificationService.cs | 5 +++ 7 files changed, 57 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad15ef1ef..cd4cac713 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [1.1.26] +### Fixed +- Bug in Snyk Code messages encoding resulting in failed Snyk Code scans. + ### Changed - Update wording in settings menu for collecting analytics. diff --git a/Snyk.Code.Library/Api/Encoding/Encoder.cs b/Snyk.Code.Library/Api/Encoding/Encoder.cs index f451a5a2b..b713f1a01 100644 --- a/Snyk.Code.Library/Api/Encoding/Encoder.cs +++ b/Snyk.Code.Library/Api/Encoding/Encoder.cs @@ -1,16 +1,21 @@ namespace Snyk.Code.Library.Api.Encoding { + using System; using System.IO; using System.IO.Compression; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; + using Serilog; + using Snyk.Common; /// /// Snyk Code API requests encoder. /// public class Encoder { + private static readonly ILogger Logger = LogManager.ForContext(); + /// /// Encodes payload to base64 and encrypts using Gzip compression. /// @@ -18,16 +23,28 @@ public class Encoder /// Encoded stream public static async Task EncodeAndCompressAsync(string payload) { - var destinationPayload = new MemoryStream(); + try + { + var destinationPayload = new MemoryStream(); + + using (var originalPayload = new MemoryStream(Encoding.UTF8.GetBytes(payload))) + using (var compressor = new GZipStream(destinationPayload, CompressionMode.Compress, true)) + using (var base64Stream = new CryptoStream(compressor, new ToBase64Transform(), CryptoStreamMode.Write)) + { + await Task.Run(() => originalPayload.CopyTo(base64Stream)); - using (var originalPayload = new MemoryStream(Encoding.UTF8.GetBytes(payload))) - using (var compressor = new GZipStream(destinationPayload, CompressionMode.Compress, true)) - using (var base64Stream = new CryptoStream(compressor, new ToBase64Transform(), CryptoStreamMode.Write)) + // Some rare errors about multiple async readers might be related to the next line. + // Removing it for now and using the blocking copy wrapped in a Task.Run() + // await originalPayload.CopyToAsync(base64Stream); + } + + return destinationPayload; + } + catch (Exception exception) { - await originalPayload.CopyToAsync(base64Stream); + Logger.Error(exception, "Error when trying to compress and encrypt payload"); + throw; } - - return destinationPayload; } } } diff --git a/Snyk.Code.Library/Api/SnykCodeClient.cs b/Snyk.Code.Library/Api/SnykCodeClient.cs index 432086f93..2eeaded13 100644 --- a/Snyk.Code.Library/Api/SnykCodeClient.cs +++ b/Snyk.Code.Library/Api/SnykCodeClient.cs @@ -17,7 +17,7 @@ public class SnykCodeClient : ISnykCodeClient /// /// Maximum bundle size per one upload is 4 Mb. 4 Mb in bytes. /// - public const int MaxBundleSize = 4000000; + public const int MaxBundleSize = 4_000_000; private const string FiltersApiUrl = "filters"; @@ -269,10 +269,15 @@ private async Task NewHttpRequestContentAsync(HttpMethod method, st // Snyk Code PUT and POST requests must be base64 encoded and deflated for certain environments (ROAD-909) if (method == HttpMethod.Put || method == HttpMethod.Post) { + Logger.Information("Encoding and compressing {Length} bytes...", System.Text.Encoding.UTF8.GetByteCount(payload)); var encodedPayload = await Encoder.EncodeAndCompressAsync(payload); - return new ByteArrayContent(encodedPayload.ToArray()); + var byteContent = encodedPayload.ToArray(); + Logger.Information("Sending {Length} bytes", byteContent.Length); + + return new ByteArrayContent(byteContent); } + Logger.Information("Sending {Length} bytes...", System.Text.Encoding.UTF8.GetByteCount(payload)); return new StringContent(payload, System.Text.Encoding.UTF8, "application/json"); } } diff --git a/Snyk.Code.Library/Service/AnalysisService.cs b/Snyk.Code.Library/Service/AnalysisService.cs index 420cc88d9..bc37f1443 100644 --- a/Snyk.Code.Library/Service/AnalysisService.cs +++ b/Snyk.Code.Library/Service/AnalysisService.cs @@ -56,7 +56,7 @@ private async Task TryGetAnalysisDtoAsync( int requestAttempts, CancellationToken cancellationToken = default) { - Logger.Debug("Try get analysis DTO object {RequestAttempts} times.", RequestAttempts); + Logger.Debug("Try get analysis DTO object {RequestAttempts} times.", requestAttempts); cancellationToken.ThrowIfCancellationRequested(); diff --git a/Snyk.Code.Library/Service/BundleService.cs b/Snyk.Code.Library/Service/BundleService.cs index 6ff30581b..389dc4622 100644 --- a/Snyk.Code.Library/Service/BundleService.cs +++ b/Snyk.Code.Library/Service/BundleService.cs @@ -123,7 +123,7 @@ public async Task UploadFilesAsync( fireScanCodeProgressUpdate(SnykCodeScanState.Preparing, 100); - return bundle.MissingFiles.Count() == 0; + return !bundle.MissingFiles.Any(); } else { @@ -315,12 +315,17 @@ public List> SplitFilesToChunkListsBySize( foreach (var filePair in pathToHashFileDict) { - cancellationToken.ThrowIfCancellationRequested(); - - int fileSize = this.CalculateFilePairSize(filePair); + var filename = filePair.Key; + cancellationToken.ThrowIfCancellationRequested(); + var fileSize = this.CalculateFilePairSize(filePair); if (fileSize > maxChunkSize) { + Logger.Information( + "Skipping file {Filename} because it's size is larger than the Snyk Code limit ({FileSize} > {MaxChunkSize})", + filename, + fileSize, + maxChunkSize); continue; // If file too big it skip it and continue to upload other files. } @@ -334,7 +339,7 @@ public List> SplitFilesToChunkListsBySize( bundleSize = 0; } - fileDictionary.Add(filePair.Key, filePair.Value); + fileDictionary.Add(filename, filePair.Value); bundleSize += fileSize; } @@ -552,20 +557,20 @@ public async Task ProcessCreateLargeBundleAsync( private int CalculateFilePairSize(KeyValuePair filePair) => this.CalculatePayloadSize(Json.Serialize(filePair)); /// - /// Claculate file pairs size. + /// Calculate file pairs size. /// /// Source dictionary with file info. /// Size of dictionary. private int CalculateFilesSize(IDictionary files) => this.CalculatePayloadSize(Json.Serialize(files)); /// - /// Claculate file pairs size. + /// Calculate file pairs size. /// /// Source dictionary with file info. private int CalculateFilesSize(IDictionary files) => this.CalculatePayloadSize(Json.Serialize(files)); /// - /// Claculate file pairs size. + /// Calculate file pairs size. /// /// Source dictionary with file info. /// Size of dictionary. diff --git a/Snyk.VisualStudio.Extension.Shared/Service/SnykTasksService.cs b/Snyk.VisualStudio.Extension.Shared/Service/SnykTasksService.cs index 17a705c08..e15c49a15 100644 --- a/Snyk.VisualStudio.Extension.Shared/Service/SnykTasksService.cs +++ b/Snyk.VisualStudio.Extension.Shared/Service/SnykTasksService.cs @@ -174,9 +174,9 @@ public void CancelTasks() this.isSnykCodeScanning = false; this.isCliDownloading = false; - this.CancelTask(this.ossScanTokenSource); - this.CancelTask(this.snykCodeScanTokenSource); - this.CancelTask(this.downloadCliTokenSource); + this.CancelTask(ref this.ossScanTokenSource); + this.CancelTask(ref this.snykCodeScanTokenSource); + this.CancelTask(ref this.downloadCliTokenSource); this.serviceProvider.OssService.StopScan(); } @@ -662,7 +662,7 @@ private IList GetSelectedFeatures(FeaturesSettings featuresSetting return selectedProducts; } - private void CancelTask(CancellationTokenSource tokenSource) + private void CancelTask(ref CancellationTokenSource tokenSource) { try { diff --git a/Snyk.VisualStudio.Extension.Shared/UI/Notifications/VsStatusBarNotificationService.cs b/Snyk.VisualStudio.Extension.Shared/UI/Notifications/VsStatusBarNotificationService.cs index ee8981e48..c7d3251b9 100644 --- a/Snyk.VisualStudio.Extension.Shared/UI/Notifications/VsStatusBarNotificationService.cs +++ b/Snyk.VisualStudio.Extension.Shared/UI/Notifications/VsStatusBarNotificationService.cs @@ -75,6 +75,11 @@ public void InitializeEventListeners(ISnykCodeService codeService, ISnykOptions private void OnOssScanError(object sender, SnykCliScanEventArgs eventArgs) { + if (this.options == null || this.statusBar == null) + { + return; + } + if (!this.options.SnykCodeSecurityEnabled && !this.options.SnykCodeQualityEnabled) { this.statusBar.ShowSnykCodeUpdateMessage("Snyk Open Source scan error");