Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ namespace Microsoft.ComponentDetection.Detectors.Spdx;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Spdx22ComponentDetector discover SPDX SBOM files in JSON format and create components with the information about
Expand Down Expand Up @@ -44,7 +43,7 @@ public Spdx22ComponentDetector(

public override IList<string> SearchPatterns => ["*.spdx.json"];

protected override Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary<string, string> detectorArgs, CancellationToken cancellationToken = default)
protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary<string, string> detectorArgs, CancellationToken cancellationToken = default)
{
this.Logger.LogDebug("Discovered SPDX2.2 manifest file at: {ManifestLocation}", processRequest.ComponentStream.Location);
var file = processRequest.ComponentStream;
Expand All @@ -56,31 +55,22 @@ protected override Task OnFileFoundAsync(ProcessRequest processRequest, IDiction
// Reset buffer to starting position after hash generation.
file.Stream.Seek(0, SeekOrigin.Begin);

using var sr = new StreamReader(file.Stream);
using var reader = new JsonTextReader(sr);
var serializer = new JsonSerializer();

try
{
var document = serializer.Deserialize<JObject>(reader);
if (document != null)
using var document = await JsonDocument.ParseAsync(file.Stream, cancellationToken: cancellationToken).ConfigureAwait(false);
var root = document.RootElement;

if (this.IsSPDXVersionSupported(root))
{
if (this.IsSPDXVersionSupported(document))
{
var sbomComponent = this.ConvertJObjectToSbomComponent(processRequest, document, hash);
processRequest.SingleFileComponentRecorder.RegisterUsage(new DetectedComponent(sbomComponent));
}
else
{
this.Logger.LogWarning("Discovered SPDX at {ManifestLocation} is not SPDX-2.2 document, skipping", processRequest.ComponentStream.Location);
}
var sbomComponent = this.ConvertJsonElementToSbomComponent(processRequest, root, hash);
processRequest.SingleFileComponentRecorder.RegisterUsage(new DetectedComponent(sbomComponent));
}
else
{
this.Logger.LogWarning("Discovered SPDX file at {ManifestLocation} is not a valid document, skipping", processRequest.ComponentStream.Location);
this.Logger.LogWarning("Discovered SPDX at {ManifestLocation} is not SPDX-2.2 document, skipping", processRequest.ComponentStream.Location);
}
}
catch (JsonReaderException)
catch (JsonException)
{
this.Logger.LogWarning("Unable to parse file at {ManifestLocation}, skipping", processRequest.ComponentStream.Location);
}
Expand All @@ -89,25 +79,40 @@ protected override Task OnFileFoundAsync(ProcessRequest processRequest, IDiction
{
this.Logger.LogError(e, "Error while processing SPDX file at {ManifestLocation}", processRequest.ComponentStream.Location);
}

return Task.CompletedTask;
}

private bool IsSPDXVersionSupported(JObject document) => this.supportedSPDXVersions.Contains(document["spdxVersion"]?.ToString(), StringComparer.OrdinalIgnoreCase);
private bool IsSPDXVersionSupported(JsonElement document)
{
if (document.TryGetProperty("spdxVersion", out var versionElement))
{
var version = versionElement.GetString();
return this.supportedSPDXVersions.Contains(version, StringComparer.OrdinalIgnoreCase);
}

private SpdxComponent ConvertJObjectToSbomComponent(ProcessRequest processRequest, JObject document, string fileHash)
return false;
}

private SpdxComponent ConvertJsonElementToSbomComponent(ProcessRequest processRequest, JsonElement document, string fileHash)
{
var sbomNamespace = document["documentNamespace"]?.ToString();
var rootElements = document["documentDescribes"]?.ToObject<string[]>();
var name = document["name"]?.ToString();
var spdxVersion = document["spdxVersion"]?.ToString();
var sbomNamespace = document.TryGetProperty("documentNamespace", out var nsElement) ? nsElement.GetString() : null;
var name = document.TryGetProperty("name", out var nameElement) ? nameElement.GetString() : null;
var spdxVersion = document.TryGetProperty("spdxVersion", out var spdxVersionElement) ? spdxVersionElement.GetString() : null;

string[] rootElements = null;
if (document.TryGetProperty("documentDescribes", out var describesElement) && describesElement.ValueKind == JsonValueKind.Array)
{
rootElements = describesElement.EnumerateArray()
.Select(e => e.GetString())
.Where(s => s != null)
.ToArray();
}

if (rootElements?.Length > 1)
if (rootElements is { Length: > 1 })
{
this.Logger.LogWarning("SPDX file at {ManifestLocation} has more than one element in documentDescribes, first will be selected as root element.", processRequest.ComponentStream.Location);
}

if (rootElements != null && rootElements.Length == 0)
if (rootElements is { Length: 0 })
{
this.Logger.LogWarning("SPDX file at {ManifestLocation} does not have root elements in documentDescribes section, considering SPDXRef-Document as a root element.", processRequest.ComponentStream.Location);
}
Expand Down