audit work, fixed StellaOps.sln warnings/errors, fixed tests, sprints work, new advisories

This commit is contained in:
master
2026-01-07 18:49:59 +02:00
parent 04ec098046
commit 608a7f85c0
866 changed files with 56323 additions and 6231 deletions

View File

@@ -0,0 +1,203 @@
// <copyright file="Spdx3VersionDetector.cs" company="StellaOps">
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
// </copyright>
using System.Text.Json;
namespace StellaOps.Spdx3;
/// <summary>
/// Detects the SPDX version of a document.
/// </summary>
public static class Spdx3VersionDetector
{
/// <summary>
/// Detected SPDX version.
/// </summary>
public enum SpdxVersion
{
/// <summary>
/// Unknown version.
/// </summary>
Unknown,
/// <summary>
/// SPDX 2.2.
/// </summary>
Spdx22,
/// <summary>
/// SPDX 2.3.
/// </summary>
Spdx23,
/// <summary>
/// SPDX 3.0.1.
/// </summary>
Spdx301
}
/// <summary>
/// Version detection result.
/// </summary>
/// <param name="Version">The detected version.</param>
/// <param name="VersionString">The raw version string if found.</param>
/// <param name="IsJsonLd">Whether the document uses JSON-LD format.</param>
public readonly record struct DetectionResult(
SpdxVersion Version,
string? VersionString,
bool IsJsonLd);
/// <summary>
/// Detects the SPDX version from a JSON document.
/// </summary>
/// <param name="json">The JSON content.</param>
/// <returns>The detection result.</returns>
public static DetectionResult Detect(string json)
{
using var document = JsonDocument.Parse(json);
return Detect(document.RootElement);
}
/// <summary>
/// Detects the SPDX version from a JSON element.
/// </summary>
/// <param name="root">The root JSON element.</param>
/// <returns>The detection result.</returns>
public static DetectionResult Detect(JsonElement root)
{
// Check for JSON-LD @context (SPDX 3.x indicator)
if (root.TryGetProperty("@context", out var context))
{
var contextStr = GetContextString(context);
if (!string.IsNullOrEmpty(contextStr))
{
// Check for specific 3.0.1 context
if (contextStr.Contains("3.0.1", StringComparison.OrdinalIgnoreCase) ||
contextStr.Contains("spdx.org/rdf/3", StringComparison.OrdinalIgnoreCase))
{
return new DetectionResult(SpdxVersion.Spdx301, "3.0.1", true);
}
// Generic 3.x detection
if (contextStr.Contains("spdx.org/rdf", StringComparison.OrdinalIgnoreCase))
{
return new DetectionResult(SpdxVersion.Spdx301, null, true);
}
}
// Has @context but couldn't determine specific version
return new DetectionResult(SpdxVersion.Spdx301, null, true);
}
// Check for SPDX 2.x spdxVersion field
if (root.TryGetProperty("spdxVersion", out var spdxVersion) &&
spdxVersion.ValueKind == JsonValueKind.String)
{
var versionStr = spdxVersion.GetString();
if (!string.IsNullOrEmpty(versionStr))
{
if (versionStr.Contains("2.3", StringComparison.OrdinalIgnoreCase))
{
return new DetectionResult(SpdxVersion.Spdx23, versionStr, false);
}
if (versionStr.Contains("2.2", StringComparison.OrdinalIgnoreCase))
{
return new DetectionResult(SpdxVersion.Spdx22, versionStr, false);
}
// Older 2.x versions
if (versionStr.StartsWith("SPDX-2", StringComparison.OrdinalIgnoreCase))
{
return new DetectionResult(SpdxVersion.Spdx22, versionStr, false);
}
}
}
// Check for creationInfo.specVersion (SPDX 3.x in @graph format)
if (root.TryGetProperty("@graph", out var graph) && graph.ValueKind == JsonValueKind.Array)
{
foreach (var element in graph.EnumerateArray())
{
if (element.TryGetProperty("creationInfo", out var creationInfo) &&
creationInfo.ValueKind == JsonValueKind.Object)
{
if (creationInfo.TryGetProperty("specVersion", out var specVersion) &&
specVersion.ValueKind == JsonValueKind.String)
{
var specVersionStr = specVersion.GetString();
if (specVersionStr == "3.0.1")
{
return new DetectionResult(SpdxVersion.Spdx301, specVersionStr, true);
}
}
}
}
}
return new DetectionResult(SpdxVersion.Unknown, null, false);
}
/// <summary>
/// Detects the SPDX version from a stream.
/// </summary>
/// <param name="stream">The input stream.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The detection result.</returns>
public static async Task<DetectionResult> DetectAsync(
Stream stream,
CancellationToken cancellationToken = default)
{
using var document = await JsonDocument.ParseAsync(stream, cancellationToken: cancellationToken)
.ConfigureAwait(false);
return Detect(document.RootElement);
}
/// <summary>
/// Gets the recommended parser for the detected version.
/// </summary>
/// <param name="version">The detected version.</param>
/// <returns>Parser recommendation.</returns>
public static string GetParserRecommendation(SpdxVersion version) => version switch
{
SpdxVersion.Spdx22 => "Use SpdxParser (SPDX 2.x parser)",
SpdxVersion.Spdx23 => "Use SpdxParser (SPDX 2.x parser)",
SpdxVersion.Spdx301 => "Use Spdx3Parser (SPDX 3.0.1 parser)",
_ => "Unknown format - manual inspection required"
};
private static string? GetContextString(JsonElement context)
{
if (context.ValueKind == JsonValueKind.String)
{
return context.GetString();
}
if (context.ValueKind == JsonValueKind.Array)
{
foreach (var item in context.EnumerateArray())
{
if (item.ValueKind == JsonValueKind.String)
{
var str = item.GetString();
if (!string.IsNullOrEmpty(str) && str.Contains("spdx", StringComparison.OrdinalIgnoreCase))
{
return str;
}
}
}
// Return first string if no spdx-specific one found
foreach (var item in context.EnumerateArray())
{
if (item.ValueKind == JsonValueKind.String)
{
return item.GetString();
}
}
}
return null;
}
}