more audit work

This commit is contained in:
master
2026-01-08 10:21:51 +02:00
parent 43c02081ef
commit 51cf4bc16c
546 changed files with 36721 additions and 4003 deletions

View File

@@ -7,6 +7,8 @@ using System.Text.Json;
using Microsoft.Extensions.Logging;
using StellaOps.Spdx3.JsonLd;
using StellaOps.Spdx3.Model;
using StellaOps.Spdx3.Model.Build;
using StellaOps.Spdx3.Model.Security;
using StellaOps.Spdx3.Model.Software;
namespace StellaOps.Spdx3;
@@ -202,6 +204,19 @@ public sealed class Spdx3Parser : ISpdx3Parser
ParseAgent<Spdx3Organization>(element, spdxId),
"Tool" or "spdx:Tool" =>
ParseAgent<Spdx3Tool>(element, spdxId),
"Build" or "build_Build" or "spdx:Build" =>
ParseBuild(element, spdxId),
"security_Vulnerability" or "Vulnerability" or "spdx:security_Vulnerability" =>
ParseVulnerability(element, spdxId),
"security_VexAffectedVulnAssessmentRelationship" or
"security_VexNotAffectedVulnAssessmentRelationship" or
"security_VexFixedVulnAssessmentRelationship" or
"security_VexUnderInvestigationVulnAssessmentRelationship" =>
ParseVexAssessment(element, spdxId, type),
"security_CvssV3VulnAssessmentRelationship" =>
ParseCvssAssessment(element, spdxId),
"security_EpssVulnAssessmentRelationship" =>
ParseEpssAssessment(element, spdxId),
_ => ParseGenericElement(element, spdxId, type, warnings)
};
}
@@ -312,6 +327,298 @@ public sealed class Spdx3Parser : ISpdx3Parser
};
}
private Spdx3Build ParseBuild(JsonElement element, string spdxId)
{
// Parse timestamps
DateTimeOffset? buildStartTime = null;
DateTimeOffset? buildEndTime = null;
var startTimeStr = GetStringProperty(element, "build_buildStartTime");
if (!string.IsNullOrEmpty(startTimeStr) && DateTimeOffset.TryParse(startTimeStr, out var parsedStart))
{
buildStartTime = parsedStart;
}
var endTimeStr = GetStringProperty(element, "build_buildEndTime");
if (!string.IsNullOrEmpty(endTimeStr) && DateTimeOffset.TryParse(endTimeStr, out var parsedEnd))
{
buildEndTime = parsedEnd;
}
// Parse config source digests
var configSourceDigests = ImmutableArray<Spdx3Hash>.Empty;
if (element.TryGetProperty("build_configSourceDigest", out var digestsElement) &&
digestsElement.ValueKind == JsonValueKind.Array)
{
var digests = new List<Spdx3Hash>();
foreach (var digestEl in digestsElement.EnumerateArray())
{
if (digestEl.ValueKind == JsonValueKind.Object)
{
var algorithm = GetStringProperty(digestEl, "algorithm") ?? "sha256";
var hashValue = GetStringProperty(digestEl, "hashValue") ?? string.Empty;
digests.Add(new Spdx3Hash { Algorithm = algorithm, HashValue = hashValue });
}
}
configSourceDigests = digests.ToImmutableArray();
}
// Parse environment and parameters as dictionaries
var environment = ParseDictionary(element, "build_environment");
var parameters = ParseDictionary(element, "build_parameter");
return new Spdx3Build
{
SpdxId = spdxId,
Type = GetStringProperty(element, "@type"),
Name = GetStringProperty(element, "name"),
Summary = GetStringProperty(element, "summary"),
Description = GetStringProperty(element, "description"),
BuildType = GetStringProperty(element, "build_buildType") ?? string.Empty,
BuildId = GetStringProperty(element, "build_buildId"),
BuildStartTime = buildStartTime,
BuildEndTime = buildEndTime,
ConfigSourceUri = GetStringArrayProperty(element, "build_configSourceUri"),
ConfigSourceDigest = configSourceDigests,
ConfigSourceEntrypoint = GetStringArrayProperty(element, "build_configSourceEntrypoint"),
Environment = environment,
Parameter = parameters,
VerifiedUsing = ParseIntegrityMethods(element),
ExternalRef = ParseExternalRefs(element),
ExternalIdentifier = ParseExternalIdentifiers(element)
};
}
private static ImmutableDictionary<string, string> ParseDictionary(JsonElement element, string propertyName)
{
if (!element.TryGetProperty(propertyName, out var dictElement) ||
dictElement.ValueKind != JsonValueKind.Object)
{
return ImmutableDictionary<string, string>.Empty;
}
var dict = new Dictionary<string, string>(StringComparer.Ordinal);
foreach (var property in dictElement.EnumerateObject())
{
if (property.Value.ValueKind == JsonValueKind.String)
{
dict[property.Name] = property.Value.GetString() ?? string.Empty;
}
}
return dict.ToImmutableDictionary();
}
private Spdx3Vulnerability ParseVulnerability(JsonElement element, string spdxId)
{
DateTimeOffset? publishedTime = null;
DateTimeOffset? modifiedTime = null;
DateTimeOffset? withdrawnTime = null;
var publishedStr = GetStringProperty(element, "security_publishedTime");
if (!string.IsNullOrEmpty(publishedStr) && DateTimeOffset.TryParse(publishedStr, out var parsedPublished))
{
publishedTime = parsedPublished;
}
var modifiedStr = GetStringProperty(element, "security_modifiedTime");
if (!string.IsNullOrEmpty(modifiedStr) && DateTimeOffset.TryParse(modifiedStr, out var parsedModified))
{
modifiedTime = parsedModified;
}
var withdrawnStr = GetStringProperty(element, "security_withdrawnTime");
if (!string.IsNullOrEmpty(withdrawnStr) && DateTimeOffset.TryParse(withdrawnStr, out var parsedWithdrawn))
{
withdrawnTime = parsedWithdrawn;
}
return new Spdx3Vulnerability
{
SpdxId = spdxId,
Type = GetStringProperty(element, "@type"),
Name = GetStringProperty(element, "name"),
Summary = GetStringProperty(element, "summary"),
Description = GetStringProperty(element, "description"),
PublishedTime = publishedTime,
ModifiedTime = modifiedTime,
WithdrawnTime = withdrawnTime,
ExternalRefs = ParseExternalRefs(element),
ExternalIdentifiers = ParseExternalIdentifiers(element)
};
}
private Spdx3VulnAssessmentRelationship ParseVexAssessment(
JsonElement element,
string spdxId,
string type)
{
var assessedElement = GetStringProperty(element, "security_assessedElement") ?? string.Empty;
var from = GetStringProperty(element, "from") ?? string.Empty;
var toValue = GetStringProperty(element, "to");
var toArray = toValue != null ? ImmutableArray.Create(toValue) : GetStringArrayProperty(element, "to");
DateTimeOffset? publishedTime = null;
var publishedStr = GetStringProperty(element, "security_publishedTime");
if (!string.IsNullOrEmpty(publishedStr) && DateTimeOffset.TryParse(publishedStr, out var parsedPublished))
{
publishedTime = parsedPublished;
}
DateTimeOffset? actionStatementTime = null;
var actionTimeStr = GetStringProperty(element, "security_actionStatementTime");
if (!string.IsNullOrEmpty(actionTimeStr) && DateTimeOffset.TryParse(actionTimeStr, out var parsedActionTime))
{
actionStatementTime = parsedActionTime;
}
var vexVersion = GetStringProperty(element, "security_vexVersion");
var statusNotes = GetStringProperty(element, "security_statusNotes");
var actionStatement = GetStringProperty(element, "security_actionStatement");
var impactStatement = GetStringProperty(element, "security_impactStatement");
var suppliedBy = GetStringProperty(element, "security_suppliedBy");
// Parse justification for not_affected
Spdx3VexJustificationType? justificationType = null;
var justificationStr = GetStringProperty(element, "security_justificationType");
if (!string.IsNullOrEmpty(justificationStr) &&
Enum.TryParse<Spdx3VexJustificationType>(justificationStr, ignoreCase: true, out var parsed))
{
justificationType = parsed;
}
return type switch
{
"security_VexAffectedVulnAssessmentRelationship" => new Spdx3VexAffectedVulnAssessmentRelationship
{
SpdxId = spdxId,
Type = type,
AssessedElement = assessedElement,
From = from,
To = toArray,
RelationshipType = Spdx3RelationshipType.Affects,
VexVersion = vexVersion,
StatusNotes = statusNotes,
ActionStatement = actionStatement,
ActionStatementTime = actionStatementTime,
PublishedTime = publishedTime,
SuppliedBy = suppliedBy
},
"security_VexNotAffectedVulnAssessmentRelationship" => new Spdx3VexNotAffectedVulnAssessmentRelationship
{
SpdxId = spdxId,
Type = type,
AssessedElement = assessedElement,
From = from,
To = toArray,
RelationshipType = Spdx3RelationshipType.DoesNotAffect,
VexVersion = vexVersion,
StatusNotes = statusNotes,
ImpactStatement = impactStatement,
JustificationType = justificationType,
PublishedTime = publishedTime,
SuppliedBy = suppliedBy
},
"security_VexFixedVulnAssessmentRelationship" => new Spdx3VexFixedVulnAssessmentRelationship
{
SpdxId = spdxId,
Type = type,
AssessedElement = assessedElement,
From = from,
To = toArray,
RelationshipType = Spdx3RelationshipType.FixedIn,
VexVersion = vexVersion,
StatusNotes = statusNotes,
PublishedTime = publishedTime,
SuppliedBy = suppliedBy
},
"security_VexUnderInvestigationVulnAssessmentRelationship" => new Spdx3VexUnderInvestigationVulnAssessmentRelationship
{
SpdxId = spdxId,
Type = type,
AssessedElement = assessedElement,
From = from,
To = toArray,
RelationshipType = Spdx3RelationshipType.UnderInvestigationFor,
VexVersion = vexVersion,
StatusNotes = statusNotes,
PublishedTime = publishedTime,
SuppliedBy = suppliedBy
},
_ => throw new ArgumentException($"Unknown VEX assessment type: {type}")
};
}
private Spdx3CvssV3VulnAssessmentRelationship ParseCvssAssessment(JsonElement element, string spdxId)
{
var assessedElement = GetStringProperty(element, "security_assessedElement") ?? string.Empty;
var from = GetStringProperty(element, "from") ?? string.Empty;
var toValue = GetStringProperty(element, "to");
var toArray = toValue != null ? ImmutableArray.Create(toValue) : GetStringArrayProperty(element, "to");
decimal? baseScore = null;
if (element.TryGetProperty("security_score", out var scoreEl) && scoreEl.TryGetDecimal(out var score))
{
baseScore = score;
}
var vectorString = GetStringProperty(element, "security_vectorString");
// Parse severity enum
Spdx3CvssSeverity? severityEnum = null;
var severityStr = GetStringProperty(element, "security_severity");
if (!string.IsNullOrEmpty(severityStr) &&
Enum.TryParse<Spdx3CvssSeverity>(severityStr, ignoreCase: true, out var parsedSeverity))
{
severityEnum = parsedSeverity;
}
return new Spdx3CvssV3VulnAssessmentRelationship
{
SpdxId = spdxId,
Type = "security_CvssV3VulnAssessmentRelationship",
AssessedElement = assessedElement,
From = from,
To = toArray,
RelationshipType = Spdx3RelationshipType.HasAssessmentFor,
Score = baseScore,
VectorString = vectorString,
Severity = severityEnum
};
}
private Spdx3EpssVulnAssessmentRelationship ParseEpssAssessment(JsonElement element, string spdxId)
{
var assessedElement = GetStringProperty(element, "security_assessedElement") ?? string.Empty;
var from = GetStringProperty(element, "from") ?? string.Empty;
var toValue = GetStringProperty(element, "to");
var toArray = toValue != null ? ImmutableArray.Create(toValue) : GetStringArrayProperty(element, "to");
decimal? probability = null;
if (element.TryGetProperty("security_probability", out var probEl) && probEl.TryGetDecimal(out var prob))
{
probability = prob;
}
decimal? percentile = null;
if (element.TryGetProperty("security_percentile", out var percEl) && percEl.TryGetDecimal(out var perc))
{
percentile = perc;
}
return new Spdx3EpssVulnAssessmentRelationship
{
SpdxId = spdxId,
Type = "security_EpssVulnAssessmentRelationship",
AssessedElement = assessedElement,
From = from,
To = toArray,
RelationshipType = Spdx3RelationshipType.HasAssessmentFor,
Probability = probability,
Percentile = percentile
};
}
private T ParseAgent<T>(JsonElement element, string spdxId) where T : Spdx3Element
{
var name = GetStringProperty(element, "name") ?? string.Empty;