294 lines
8.4 KiB
C#
294 lines
8.4 KiB
C#
// <copyright file="IVexToSpdx3Mapper.cs" company="StellaOps">
|
|
// Copyright (c) StellaOps. Licensed under the BUSL-1.1.
|
|
// </copyright>
|
|
|
|
using StellaOps.Spdx3.Model;
|
|
|
|
namespace StellaOps.VexLens.Spdx3;
|
|
|
|
/// <summary>
|
|
/// Interface for mapping VEX consensus results to SPDX 3.0.1 Security profile documents.
|
|
/// Sprint: SPRINT_20260107_004_004 Task SP-005
|
|
/// </summary>
|
|
public interface IVexToSpdx3Mapper
|
|
{
|
|
/// <summary>
|
|
/// Maps a VEX consensus result to an SPDX 3.0.1 document with Security profile.
|
|
/// </summary>
|
|
/// <param name="consensus">The VEX consensus containing statements.</param>
|
|
/// <param name="options">Mapping options.</param>
|
|
/// <param name="cancellationToken">Cancellation token.</param>
|
|
/// <returns>The mapped SPDX 3.0.1 document.</returns>
|
|
Task<Spdx3Document> MapConsensusAsync(
|
|
VexConsensus consensus,
|
|
VexToSpdx3Options options,
|
|
CancellationToken cancellationToken = default);
|
|
|
|
/// <summary>
|
|
/// Maps individual VEX statements to SPDX 3.0.1 elements.
|
|
/// </summary>
|
|
/// <param name="statements">The VEX statements to map.</param>
|
|
/// <param name="spdxIdPrefix">Prefix for generating SPDX IDs.</param>
|
|
/// <returns>The mapped elements including vulnerabilities and assessment relationships.</returns>
|
|
VexMappingResult MapStatements(
|
|
IEnumerable<OpenVexStatement> statements,
|
|
string spdxIdPrefix);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Options for VEX to SPDX 3.0.1 mapping.
|
|
/// </summary>
|
|
public sealed record VexToSpdx3Options
|
|
{
|
|
/// <summary>
|
|
/// Gets the SPDX ID prefix for generated elements.
|
|
/// </summary>
|
|
public required string SpdxIdPrefix { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the document name.
|
|
/// </summary>
|
|
public string? DocumentName { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets whether to include CVSS scores.
|
|
/// </summary>
|
|
public bool IncludeCvss { get; init; } = true;
|
|
|
|
/// <summary>
|
|
/// Gets whether to include EPSS scores.
|
|
/// </summary>
|
|
public bool IncludeEpss { get; init; } = true;
|
|
|
|
/// <summary>
|
|
/// Gets the tool identifier to include in creation info.
|
|
/// </summary>
|
|
public string ToolId { get; init; } = "StellaOps VexLens";
|
|
|
|
/// <summary>
|
|
/// Gets a filter for specific products (null = all).
|
|
/// </summary>
|
|
public IReadOnlyList<string>? ProductFilter { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets a filter for specific CVEs (null = all).
|
|
/// </summary>
|
|
public IReadOnlyList<string>? VulnerabilityFilter { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Result of mapping VEX statements to SPDX 3.0.1 elements.
|
|
/// </summary>
|
|
public sealed record VexMappingResult
|
|
{
|
|
/// <summary>
|
|
/// Gets the vulnerability elements.
|
|
/// </summary>
|
|
public required IReadOnlyList<Spdx3Element> Vulnerabilities { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the VEX assessment relationships.
|
|
/// </summary>
|
|
public required IReadOnlyList<Spdx3Element> Assessments { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the CVSS assessment relationships.
|
|
/// </summary>
|
|
public IReadOnlyList<Spdx3Element> CvssAssessments { get; init; } = Array.Empty<Spdx3Element>();
|
|
|
|
/// <summary>
|
|
/// Gets the EPSS assessment relationships.
|
|
/// </summary>
|
|
public IReadOnlyList<Spdx3Element> EpssAssessments { get; init; } = Array.Empty<Spdx3Element>();
|
|
|
|
/// <summary>
|
|
/// Gets all elements combined.
|
|
/// </summary>
|
|
public IEnumerable<Spdx3Element> AllElements =>
|
|
Vulnerabilities
|
|
.Concat(Assessments)
|
|
.Concat(CvssAssessments)
|
|
.Concat(EpssAssessments);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents a VEX consensus containing multiple statements.
|
|
/// </summary>
|
|
public sealed record VexConsensus
|
|
{
|
|
/// <summary>
|
|
/// Gets the document identifier.
|
|
/// </summary>
|
|
public required string DocumentId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the document version.
|
|
/// </summary>
|
|
public string? Version { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the statements in this consensus.
|
|
/// </summary>
|
|
public required IReadOnlyList<OpenVexStatement> Statements { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the supplier/author.
|
|
/// </summary>
|
|
public string? Author { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the timestamp.
|
|
/// </summary>
|
|
public DateTimeOffset? Timestamp { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents an OpenVEX statement.
|
|
/// </summary>
|
|
public sealed record OpenVexStatement
|
|
{
|
|
/// <summary>
|
|
/// Gets the vulnerability ID (e.g., CVE-2026-1234).
|
|
/// </summary>
|
|
public required string VulnerabilityId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the product ID (e.g., PURL).
|
|
/// </summary>
|
|
public required string ProductId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the VEX status.
|
|
/// </summary>
|
|
public required VexStatus Status { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the justification for not_affected status.
|
|
/// </summary>
|
|
public VexJustification? Justification { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the status notes.
|
|
/// </summary>
|
|
public string? StatusNotes { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the impact statement.
|
|
/// </summary>
|
|
public string? ImpactStatement { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the action statement for affected status.
|
|
/// </summary>
|
|
public string? ActionStatement { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the action statement deadline.
|
|
/// </summary>
|
|
public DateTimeOffset? ActionStatementTime { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the statement timestamp.
|
|
/// </summary>
|
|
public DateTimeOffset? Timestamp { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets the supplier/author.
|
|
/// </summary>
|
|
public string? Supplier { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets CVSS v3 data if available.
|
|
/// </summary>
|
|
public CvssV3Data? CvssV3 { get; init; }
|
|
|
|
/// <summary>
|
|
/// Gets EPSS data if available.
|
|
/// </summary>
|
|
public EpssData? Epss { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// VEX status values.
|
|
/// </summary>
|
|
public enum VexStatus
|
|
{
|
|
/// <summary>The product is affected by the vulnerability.</summary>
|
|
Affected,
|
|
|
|
/// <summary>The product is not affected by the vulnerability.</summary>
|
|
NotAffected,
|
|
|
|
/// <summary>The vulnerability is fixed in the product.</summary>
|
|
Fixed,
|
|
|
|
/// <summary>The status is under investigation.</summary>
|
|
UnderInvestigation
|
|
}
|
|
|
|
/// <summary>
|
|
/// VEX justification values for not_affected status.
|
|
/// </summary>
|
|
public enum VexJustification
|
|
{
|
|
/// <summary>The component is not present.</summary>
|
|
ComponentNotPresent,
|
|
|
|
/// <summary>The vulnerable code is not present.</summary>
|
|
VulnerableCodeNotPresent,
|
|
|
|
/// <summary>The vulnerable code cannot be controlled by an adversary.</summary>
|
|
VulnerableCodeCannotBeControlledByAdversary,
|
|
|
|
/// <summary>The vulnerable code is not in the execute path.</summary>
|
|
VulnerableCodeNotInExecutePath,
|
|
|
|
/// <summary>Inline mitigations already exist.</summary>
|
|
InlineMitigationsAlreadyExist
|
|
}
|
|
|
|
/// <summary>
|
|
/// CVSS v3 scoring data.
|
|
/// Sprint: SPRINT_20260107_004_004 Task SP-007
|
|
/// </summary>
|
|
public sealed record CvssV3Data
|
|
{
|
|
/// <summary>Gets the CVSS v3 base score (0.0-10.0).</summary>
|
|
public decimal? BaseScore { get; init; }
|
|
|
|
/// <summary>Gets the CVSS v3 vector string.</summary>
|
|
public string? VectorString { get; init; }
|
|
|
|
/// <summary>Gets the temporal score if available.</summary>
|
|
public decimal? TemporalScore { get; init; }
|
|
|
|
/// <summary>Gets the environmental score if available.</summary>
|
|
public decimal? EnvironmentalScore { get; init; }
|
|
|
|
/// <summary>Gets when the score was published.</summary>
|
|
public DateTimeOffset? PublishedTime { get; init; }
|
|
|
|
/// <summary>Gets when the score was modified.</summary>
|
|
public DateTimeOffset? ModifiedTime { get; init; }
|
|
|
|
/// <summary>Gets the source of the CVSS data.</summary>
|
|
public string? Source { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// EPSS (Exploit Prediction Scoring System) data.
|
|
/// Sprint: SPRINT_20260107_004_004 Task SP-007
|
|
/// </summary>
|
|
public sealed record EpssData
|
|
{
|
|
/// <summary>Gets the EPSS probability (0.0-1.0).</summary>
|
|
public decimal? Probability { get; init; }
|
|
|
|
/// <summary>Gets the EPSS percentile (0.0-1.0).</summary>
|
|
public decimal? Percentile { get; init; }
|
|
|
|
/// <summary>Gets the date of the EPSS score.</summary>
|
|
public DateTimeOffset? ScoreDate { get; init; }
|
|
}
|
|
|