more audit work
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
// <copyright file="Spdx3CvssVulnAssessmentRelationship.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Spdx3.Model.Security;
|
||||
|
||||
/// <summary>
|
||||
/// SPDX 3.0.1 CVSS v3 vulnerability assessment relationship.
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
public sealed record Spdx3CvssV3VulnAssessmentRelationship : Spdx3VulnAssessmentRelationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the JSON-LD type for CVSS v3 assessment.
|
||||
/// </summary>
|
||||
public const string TypeName = "security_CvssV3VulnAssessmentRelationship";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CVSS v3 score (0.0-10.0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_score")]
|
||||
public decimal? Score { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CVSS v3 severity.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_severity")]
|
||||
public Spdx3CvssSeverity? Severity { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CVSS v3 vector string.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_vectorString")]
|
||||
public string? VectorString { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SPDX 3.0.1 EPSS vulnerability assessment relationship.
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
public sealed record Spdx3EpssVulnAssessmentRelationship : Spdx3VulnAssessmentRelationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the JSON-LD type for EPSS assessment.
|
||||
/// </summary>
|
||||
public const string TypeName = "security_EpssVulnAssessmentRelationship";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EPSS probability (0.0-1.0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_probability")]
|
||||
public decimal? Probability { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EPSS percentile (0.0-1.0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_percentile")]
|
||||
public decimal? Percentile { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CVSS severity levels.
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum Spdx3CvssSeverity
|
||||
{
|
||||
/// <summary>No severity (score 0.0).</summary>
|
||||
None,
|
||||
|
||||
/// <summary>Low severity (0.1-3.9).</summary>
|
||||
Low,
|
||||
|
||||
/// <summary>Medium severity (4.0-6.9).</summary>
|
||||
Medium,
|
||||
|
||||
/// <summary>High severity (7.0-8.9).</summary>
|
||||
High,
|
||||
|
||||
/// <summary>Critical severity (9.0-10.0).</summary>
|
||||
Critical
|
||||
}
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
// <copyright file="Spdx3Vulnerability.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Spdx3.Model.Security;
|
||||
|
||||
/// <summary>
|
||||
/// SPDX 3.0.1 Vulnerability element representing a security vulnerability.
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
public sealed record Spdx3Vulnerability : Spdx3Element
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the JSON-LD type for Vulnerability elements.
|
||||
/// </summary>
|
||||
public const string TypeName = "security_Vulnerability";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the published date of the vulnerability.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_publishedTime")]
|
||||
public DateTimeOffset? PublishedTime { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the last modified date of the vulnerability.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_modifiedTime")]
|
||||
public DateTimeOffset? ModifiedTime { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the withdrawn date (if applicable).
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_withdrawnTime")]
|
||||
public DateTimeOffset? WithdrawnTime { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets external references (CVE, GHSA, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("externalRef")]
|
||||
public ImmutableArray<Spdx3ExternalRef> ExternalRefs { get; init; } = ImmutableArray<Spdx3ExternalRef>.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets external identifiers (CVE ID, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("externalIdentifier")]
|
||||
public ImmutableArray<Spdx3ExternalIdentifier> ExternalIdentifiers { get; init; } = ImmutableArray<Spdx3ExternalIdentifier>.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for SPDX 3.0.1 vulnerability assessment relationships.
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
public abstract record Spdx3VulnAssessmentRelationship : Spdx3Relationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the element being assessed (Package, File, etc.).
|
||||
/// </summary>
|
||||
[Required]
|
||||
[JsonPropertyName("security_assessedElement")]
|
||||
public required string AssessedElement { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the agent that supplied this assessment.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_suppliedBy")]
|
||||
public string? SuppliedBy { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets when the assessment was published.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_publishedTime")]
|
||||
public DateTimeOffset? PublishedTime { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets when the assessment was last modified.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_modifiedTime")]
|
||||
public DateTimeOffset? ModifiedTime { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets when the assessment was withdrawn (if applicable).
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_withdrawnTime")]
|
||||
public DateTimeOffset? WithdrawnTime { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SPDX 3.0.1 VEX Affected vulnerability assessment relationship.
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
public sealed record Spdx3VexAffectedVulnAssessmentRelationship : Spdx3VulnAssessmentRelationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the JSON-LD type for VEX Affected assessment.
|
||||
/// </summary>
|
||||
public const string TypeName = "security_VexAffectedVulnAssessmentRelationship";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the VEX version.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_vexVersion")]
|
||||
public string? VexVersion { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status notes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_statusNotes")]
|
||||
public string? StatusNotes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the action statement for remediation.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_actionStatement")]
|
||||
public string? ActionStatement { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the deadline for taking action.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_actionStatementTime")]
|
||||
public DateTimeOffset? ActionStatementTime { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SPDX 3.0.1 VEX Not Affected vulnerability assessment relationship.
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
public sealed record Spdx3VexNotAffectedVulnAssessmentRelationship : Spdx3VulnAssessmentRelationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the JSON-LD type for VEX Not Affected assessment.
|
||||
/// </summary>
|
||||
public const string TypeName = "security_VexNotAffectedVulnAssessmentRelationship";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the VEX version.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_vexVersion")]
|
||||
public string? VexVersion { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status notes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_statusNotes")]
|
||||
public string? StatusNotes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the justification for not affected status.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_justificationType")]
|
||||
public Spdx3VexJustificationType? JustificationType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the impact statement.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_impactStatement")]
|
||||
public string? ImpactStatement { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the impact statement time.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_impactStatementTime")]
|
||||
public DateTimeOffset? ImpactStatementTime { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SPDX 3.0.1 VEX Fixed vulnerability assessment relationship.
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
public sealed record Spdx3VexFixedVulnAssessmentRelationship : Spdx3VulnAssessmentRelationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the JSON-LD type for VEX Fixed assessment.
|
||||
/// </summary>
|
||||
public const string TypeName = "security_VexFixedVulnAssessmentRelationship";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the VEX version.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_vexVersion")]
|
||||
public string? VexVersion { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status notes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_statusNotes")]
|
||||
public string? StatusNotes { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SPDX 3.0.1 VEX Under Investigation vulnerability assessment relationship.
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
public sealed record Spdx3VexUnderInvestigationVulnAssessmentRelationship : Spdx3VulnAssessmentRelationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the JSON-LD type for VEX Under Investigation assessment.
|
||||
/// </summary>
|
||||
public const string TypeName = "security_VexUnderInvestigationVulnAssessmentRelationship";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the VEX version.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_vexVersion")]
|
||||
public string? VexVersion { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status notes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("security_statusNotes")]
|
||||
public string? StatusNotes { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SPDX 3.0.1 VEX justification types (from spec).
|
||||
/// Sprint: SPRINT_20260107_004_004 Task SP-001
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum Spdx3VexJustificationType
|
||||
{
|
||||
/// <summary>Component is not present.</summary>
|
||||
ComponentNotPresent,
|
||||
|
||||
/// <summary>Vulnerable code is not present.</summary>
|
||||
VulnerableCodeNotPresent,
|
||||
|
||||
/// <summary>Vulnerable code cannot be controlled by adversary.</summary>
|
||||
VulnerableCodeCannotBeControlledByAdversary,
|
||||
|
||||
/// <summary>Vulnerable code is not in execute path.</summary>
|
||||
VulnerableCodeNotInExecutePath,
|
||||
|
||||
/// <summary>Inline mitigations already exist.</summary>
|
||||
InlineMitigationsAlreadyExist
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace StellaOps.Spdx3.Model;
|
||||
/// <summary>
|
||||
/// Represents a relationship between SPDX 3.0.1 elements.
|
||||
/// </summary>
|
||||
public sealed record Spdx3Relationship : Spdx3Element
|
||||
public record Spdx3Relationship : Spdx3Element
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the source element of the relationship.
|
||||
@@ -234,6 +234,31 @@ public enum Spdx3RelationshipType
|
||||
/// </summary>
|
||||
HasEvidence,
|
||||
|
||||
/// <summary>
|
||||
/// Element A affects Element B (Security profile - VEX affected).
|
||||
/// </summary>
|
||||
Affects,
|
||||
|
||||
/// <summary>
|
||||
/// Element A does not affect Element B (Security profile - VEX not affected).
|
||||
/// </summary>
|
||||
DoesNotAffect,
|
||||
|
||||
/// <summary>
|
||||
/// Element A is fixed in Element B (Security profile - VEX fixed).
|
||||
/// </summary>
|
||||
FixedIn,
|
||||
|
||||
/// <summary>
|
||||
/// Element A is under investigation for Element B (Security profile - VEX).
|
||||
/// </summary>
|
||||
UnderInvestigationFor,
|
||||
|
||||
/// <summary>
|
||||
/// Element A has an assessment for Element B (Security profile - CVSS/EPSS).
|
||||
/// </summary>
|
||||
HasAssessmentFor,
|
||||
|
||||
/// <summary>
|
||||
/// Other relationship type (requires comment).
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user