Skip to content

Commit 7a68c61

Browse files
authored
Merge branch 'main' into users/jasonpaulos/add-linux-syft-scope-param
2 parents 36db1f8 + 2ed2e3b commit 7a68c61

16 files changed

+382
-17
lines changed

src/Microsoft.ComponentDetection.Contracts/FileComponentDetector.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ private async Task<IndividualDetectorScanResult> ProcessAsync(
125125
MaxDegreeOfParallelism = threadsToUse,
126126
});
127127

128-
var preprocessedObserbable = await this.OnPrepareDetectionAsync(processRequests, detectorArgs, cancellationToken);
128+
var preprocessedObservable = await this.OnPrepareDetectionAsync(processRequests, detectorArgs, cancellationToken);
129129

130-
await preprocessedObserbable.ForEachAsync(processRequest => processor.Post(processRequest));
130+
await preprocessedObservable.ForEachAsync(processRequest => processor.Post(processRequest));
131131

132132
processor.Complete();
133133

src/Microsoft.ComponentDetection.Detectors/pip/IPyPiClient.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,25 @@ public async Task<PythonProject> GetProjectAsync(PipDependencySpecification spec
207207
}
208208

209209
var response = await request.Content.ReadAsStringAsync();
210-
var project = JsonSerializer.Deserialize<PythonProject>(response);
210+
211+
// System.Text.Json throws on empty strings, unlike Newtonsoft.Json which returned null
212+
if (string.IsNullOrWhiteSpace(response))
213+
{
214+
this.logger.LogWarning("Empty response from PyPI for {SpecName}", spec.Name);
215+
return new PythonProject();
216+
}
217+
218+
PythonProject project;
219+
try
220+
{
221+
project = JsonSerializer.Deserialize<PythonProject>(response);
222+
}
223+
catch (JsonException ex)
224+
{
225+
this.logger.LogWarning(ex, "Invalid JSON response from PyPI for {SpecName}", spec.Name);
226+
return new PythonProject();
227+
}
228+
211229
var versions = new PythonProject
212230
{
213231
Info = project.Info,

src/Microsoft.ComponentDetection.Detectors/pip/PipCommandService.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,23 @@ private async Task<CommandLineExecutionResult> ExecuteCommandAsync(
215215
}
216216

217217
var reportOutput = await this.fileUtilityService.ReadAllTextAsync(reportFile);
218-
return (JsonSerializer.Deserialize<PipInstallationReport>(reportOutput), reportFile);
218+
219+
if (string.IsNullOrWhiteSpace(reportOutput))
220+
{
221+
throw new InvalidOperationException($"PipReport: Empty pip installation report for file {path}.");
222+
}
223+
224+
PipInstallationReport report;
225+
try
226+
{
227+
report = JsonSerializer.Deserialize<PipInstallationReport>(reportOutput);
228+
}
229+
catch (JsonException ex)
230+
{
231+
throw new InvalidOperationException($"PipReport: Invalid generated pip installation report JSON for {path}.", ex);
232+
}
233+
234+
return (report, reportFile);
219235
}
220236
finally
221237
{

src/Microsoft.ComponentDetection.Detectors/pip/PipReportComponentDetector.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,24 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID
200200
{
201201
this.Logger.LogInformation("PipReport: Using pre-generated pip report '{ReportFile}' for package file '{File}'.", existingReport.FullName, file.Location);
202202
var reportOutput = await this.fileUtilityService.ReadAllTextAsync(existingReport);
203-
var report = JsonSerializer.Deserialize<PipInstallationReport>(reportOutput);
203+
204+
// System.Text.Json throws on empty strings, unlike Newtonsoft.Json which returned null
205+
if (string.IsNullOrWhiteSpace(reportOutput))
206+
{
207+
this.Logger.LogDebug("PipReport: Empty report file '{ReportFile}' for package file '{File}'.", existingReport.FullName, file.Location);
208+
continue;
209+
}
210+
211+
PipInstallationReport report;
212+
try
213+
{
214+
report = JsonSerializer.Deserialize<PipInstallationReport>(reportOutput);
215+
}
216+
catch (JsonException ex)
217+
{
218+
this.Logger.LogWarning(ex, "PipReport: Invalid JSON in report file '{ReportFile}' for package file '{File}'.", existingReport.FullName, file.Location);
219+
continue;
220+
}
204221

205222
if (await this.IsValidPreGeneratedReportAsync(report, pythonExePath, file.Location))
206223
{
@@ -234,8 +251,16 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID
234251

235252
// Call pip executable to generate the installation report of a given project file.
236253
(var report, var reportFile) = await this.pipCommandService.GenerateInstallationReportAsync(file.Location, pipExePath, pythonExePath, childCts.Token);
237-
reports.Add(report);
238-
reportFiles.Add(reportFile);
254+
255+
if (report is not null)
256+
{
257+
reports.Add(report);
258+
}
259+
260+
if (reportFile is not null)
261+
{
262+
reportFiles.Add(reportFile);
263+
}
239264
}
240265

241266
if (reports.Count == 0)

src/Microsoft.ComponentDetection.Detectors/swiftpm/SwiftResolvedComponentDetector.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ private void ProcessPackageResolvedFile(ISingleFileComponentRecorder singleFileC
6262
{
6363
var parsedResolvedFile = this.ReadAndParseResolvedFile(componentStream.Stream);
6464

65+
if (parsedResolvedFile?.Pins == null)
66+
{
67+
this.Logger.LogWarning("Failed to parse Package.resolved file at {Location}", componentStream.Location);
68+
return;
69+
}
70+
6571
foreach (var package in parsedResolvedFile.Pins)
6672
{
6773
try
@@ -109,6 +115,21 @@ private SwiftResolvedFile ReadAndParseResolvedFile(Stream stream)
109115
resolvedFile = reader.ReadToEnd();
110116
}
111117

112-
return JsonSerializer.Deserialize<SwiftResolvedFile>(resolvedFile);
118+
// System.Text.Json throws on empty strings, unlike Newtonsoft.Json which returned null
119+
if (string.IsNullOrWhiteSpace(resolvedFile))
120+
{
121+
this.Logger.LogDebug("Empty Package.resolved file encountered");
122+
return null;
123+
}
124+
125+
try
126+
{
127+
return JsonSerializer.Deserialize<SwiftResolvedFile>(resolvedFile);
128+
}
129+
catch (JsonException ex)
130+
{
131+
this.Logger.LogWarning(ex, "Invalid JSON in Package.resolved file");
132+
return null;
133+
}
113134
}
114135
}

src/Microsoft.ComponentDetection.Detectors/vcpkg/VcpkgComponentDetector.cs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ protected override async Task<IObservable<ProcessRequest>> OnPrepareDetectionAsy
7171
{
7272
var filteredProcessRequests = new List<ProcessRequest>();
7373

74-
await processRequests.ForEachAsync(async pr =>
74+
await processRequests.ForEachAsync(pr =>
7575
{
7676
var fileLocation = pr.ComponentStream.Location;
7777
var fileName = Path.GetFileName(fileLocation);
@@ -80,18 +80,42 @@ await processRequests.ForEachAsync(async pr =>
8080
{
8181
this.Logger.LogDebug("Discovered VCPKG package manifest file at: {Location}", pr.ComponentStream.Location);
8282

83-
using (var reader = new StreamReader(pr.ComponentStream.Stream))
83+
using var reader = new StreamReader(pr.ComponentStream.Stream);
84+
85+
string contents;
86+
try
87+
{
88+
contents = reader.ReadToEnd();
89+
}
90+
catch (Exception ex)
8491
{
85-
var contents = await reader.ReadToEndAsync().ConfigureAwait(false);
86-
var manifestData = JsonSerializer.Deserialize<ManifestInfo>(contents);
92+
this.Logger.LogDebug(ex, "Failed to read {ManifestInfoFile} at {Path}", ManifestInfoFile, pr.ComponentStream.Location);
93+
return;
94+
}
8795

88-
if (manifestData == null || string.IsNullOrWhiteSpace(manifestData.ManifestPath))
96+
// System.Text.Json throws on empty strings, unlike Newtonsoft.Json which returned null
97+
if (string.IsNullOrWhiteSpace(contents))
98+
{
99+
this.Logger.LogDebug("Empty {ManifestInfoFile} file at {Path}", ManifestInfoFile, pr.ComponentStream.Location);
100+
}
101+
else
102+
{
103+
try
89104
{
90-
this.Logger.LogDebug("Failed to deserialize manifest-info.json or missing ManifestPath at {Path}", pr.ComponentStream.Location);
105+
var manifestData = JsonSerializer.Deserialize<ManifestInfo>(contents);
106+
107+
if (string.IsNullOrWhiteSpace(manifestData?.ManifestPath))
108+
{
109+
this.Logger.LogDebug("Failed to deserialize {ManifestInfoFile} or missing ManifestPath at {Path}", ManifestInfoFile, pr.ComponentStream.Location);
110+
}
111+
else
112+
{
113+
this.manifestMappings.TryAdd(fileLocation, manifestData.ManifestPath);
114+
}
91115
}
92-
else
116+
catch (JsonException ex)
93117
{
94-
this.manifestMappings.TryAdd(fileLocation, manifestData.ManifestPath);
118+
this.Logger.LogWarning(ex, "Invalid JSON in {ManifestInfoFile} at {Path}", ManifestInfoFile, pr.ComponentStream.Location);
95119
}
96120
}
97121
}
@@ -211,7 +235,8 @@ private ISingleFileComponentRecorder GetManifestComponentRecorder(ISingleFileCom
211235
}
212236

213237
this.Logger.LogDebug(
214-
"No valid manifest-info.json found at either '{PreferredManifest}' or '{FallbackManifest}' for base location '{VcpkgInstalledDir}'. Returning original recorder.",
238+
"No valid {ManifestInfoFile} found at either '{PreferredManifest}' or '{FallbackManifest}' for base location '{VcpkgInstalledDir}'. Returning original recorder.",
239+
ManifestInfoFile,
215240
preferredManifest,
216241
fallbackManifest,
217242
vcpkgInstalledDir);

test/Microsoft.ComponentDetection.Detectors.Tests/Microsoft.ComponentDetection.Detectors.Tests.csproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@
5757
<None Update="Mocks\test.component-detection-pip-report.json">
5858
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
5959
</None>
60+
<None Update="Mocks\EmptyReport\requirements.txt">
61+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
62+
</None>
63+
<None Update="Mocks\EmptyReport\test.component-detection-pip-report.json">
64+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
65+
</None>
66+
<None Update="Mocks\InvalidJsonReport\requirements.txt">
67+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
68+
</None>
69+
<None Update="Mocks\InvalidJsonReport\test.component-detection-pip-report.json">
70+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
71+
</None>
6072
<None Update="TestFiles\go_WithLocalReferences.mod">
6173
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
6274
</None>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
requests==2.28.1

test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/EmptyReport/test.component-detection-pip-report.json

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
requests==2.28.1

0 commit comments

Comments
 (0)