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

@@ -0,0 +1,269 @@
// <copyright file="VulnerabilityElementBuilder.cs" company="StellaOps">
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
// </copyright>
using System.Collections.Immutable;
using System.Globalization;
using StellaOps.Spdx3.Model;
using StellaOps.Spdx3.Model.Security;
namespace StellaOps.VexLens.Spdx3;
/// <summary>
/// Builds SPDX 3.0.1 Vulnerability elements from CVE and other vulnerability data.
/// Sprint: SPRINT_20260107_004_004 Task SP-004
/// </summary>
public sealed class VulnerabilityElementBuilder
{
private readonly string _spdxIdPrefix;
private readonly List<Spdx3ExternalIdentifier> _externalIdentifiers = new();
private readonly List<Spdx3ExternalRef> _externalRefs = new();
private string? _vulnerabilityId;
private string? _description;
private DateTimeOffset? _publishedTime;
private DateTimeOffset? _modifiedTime;
/// <summary>
/// Initializes a new instance of the <see cref="VulnerabilityElementBuilder"/> class.
/// </summary>
/// <param name="spdxIdPrefix">Prefix for generating SPDX IDs.</param>
public VulnerabilityElementBuilder(string spdxIdPrefix)
{
ArgumentException.ThrowIfNullOrWhiteSpace(spdxIdPrefix);
_spdxIdPrefix = spdxIdPrefix;
}
/// <summary>
/// Sets the vulnerability ID (e.g., CVE-2026-1234).
/// </summary>
/// <param name="vulnerabilityId">The vulnerability ID.</param>
/// <returns>This builder for fluent chaining.</returns>
public VulnerabilityElementBuilder WithVulnerabilityId(string vulnerabilityId)
{
ArgumentException.ThrowIfNullOrWhiteSpace(vulnerabilityId);
_vulnerabilityId = vulnerabilityId;
// Auto-detect identifier type and add external identifier
if (vulnerabilityId.StartsWith("CVE-", StringComparison.OrdinalIgnoreCase))
{
_externalIdentifiers.Add(new Spdx3ExternalIdentifier
{
ExternalIdentifierType = "cve",
Identifier = vulnerabilityId,
IdentifierLocator = ImmutableArray.Create($"https://nvd.nist.gov/vuln/detail/{vulnerabilityId}")
});
}
else if (vulnerabilityId.StartsWith("GHSA-", StringComparison.OrdinalIgnoreCase))
{
_externalIdentifiers.Add(new Spdx3ExternalIdentifier
{
ExternalIdentifierType = "ghsa",
Identifier = vulnerabilityId,
IdentifierLocator = ImmutableArray.Create($"https://github.com/advisories/{vulnerabilityId}")
});
}
else if (vulnerabilityId.StartsWith("OSV-", StringComparison.OrdinalIgnoreCase))
{
_externalIdentifiers.Add(new Spdx3ExternalIdentifier
{
ExternalIdentifierType = "osv",
Identifier = vulnerabilityId,
IdentifierLocator = ImmutableArray.Create($"https://osv.dev/vulnerability/{vulnerabilityId}")
});
}
return this;
}
/// <summary>
/// Sets the vulnerability description.
/// </summary>
/// <param name="description">The description text.</param>
/// <returns>This builder for fluent chaining.</returns>
public VulnerabilityElementBuilder WithDescription(string? description)
{
_description = description;
return this;
}
/// <summary>
/// Sets the published time.
/// </summary>
/// <param name="publishedTime">When the vulnerability was published.</param>
/// <returns>This builder for fluent chaining.</returns>
public VulnerabilityElementBuilder WithPublishedTime(DateTimeOffset? publishedTime)
{
_publishedTime = publishedTime;
return this;
}
/// <summary>
/// Sets the modified time.
/// </summary>
/// <param name="modifiedTime">When the vulnerability was last modified.</param>
/// <returns>This builder for fluent chaining.</returns>
public VulnerabilityElementBuilder WithModifiedTime(DateTimeOffset? modifiedTime)
{
_modifiedTime = modifiedTime;
return this;
}
/// <summary>
/// Adds a reference to NVD.
/// </summary>
/// <param name="cveId">The CVE ID for NVD lookup.</param>
/// <returns>This builder for fluent chaining.</returns>
public VulnerabilityElementBuilder WithNvdReference(string cveId)
{
ArgumentException.ThrowIfNullOrWhiteSpace(cveId);
_externalRefs.Add(new Spdx3ExternalRef
{
ExternalRefType = "securityAdvisory",
Locator = ImmutableArray.Create($"https://nvd.nist.gov/vuln/detail/{cveId}")
});
return this;
}
/// <summary>
/// Adds a reference to OSV.
/// </summary>
/// <param name="vulnerabilityId">The vulnerability ID for OSV lookup.</param>
/// <returns>This builder for fluent chaining.</returns>
public VulnerabilityElementBuilder WithOsvReference(string vulnerabilityId)
{
ArgumentException.ThrowIfNullOrWhiteSpace(vulnerabilityId);
_externalRefs.Add(new Spdx3ExternalRef
{
ExternalRefType = "securityAdvisory",
Locator = ImmutableArray.Create($"https://osv.dev/vulnerability/{vulnerabilityId}")
});
return this;
}
/// <summary>
/// Adds a custom external reference.
/// </summary>
/// <param name="refType">The reference type.</param>
/// <param name="locator">The reference URL.</param>
/// <returns>This builder for fluent chaining.</returns>
public VulnerabilityElementBuilder WithExternalRef(string refType, string locator)
{
ArgumentException.ThrowIfNullOrWhiteSpace(refType);
ArgumentException.ThrowIfNullOrWhiteSpace(locator);
_externalRefs.Add(new Spdx3ExternalRef
{
ExternalRefType = refType,
Locator = ImmutableArray.Create(locator)
});
return this;
}
/// <summary>
/// Builds the SPDX 3.0.1 Vulnerability element.
/// </summary>
/// <returns>The constructed Vulnerability element.</returns>
/// <exception cref="InvalidOperationException">If vulnerability ID is not set.</exception>
public Spdx3Vulnerability Build()
{
if (string.IsNullOrWhiteSpace(_vulnerabilityId))
{
throw new InvalidOperationException("Vulnerability ID is required. Call WithVulnerabilityId() first.");
}
return new Spdx3Vulnerability
{
SpdxId = GenerateSpdxId(),
Type = Spdx3Vulnerability.TypeName,
Name = _vulnerabilityId,
Description = _description,
PublishedTime = _publishedTime,
ModifiedTime = _modifiedTime,
ExternalIdentifiers = _externalIdentifiers.ToImmutableArray(),
ExternalRefs = _externalRefs.ToImmutableArray()
};
}
/// <summary>
/// Creates a Vulnerability element from a CVE ID with NVD reference.
/// </summary>
/// <param name="cveId">The CVE ID.</param>
/// <param name="spdxIdPrefix">Prefix for SPDX ID generation.</param>
/// <param name="description">Optional description.</param>
/// <returns>The constructed Vulnerability element.</returns>
public static Spdx3Vulnerability FromCve(
string cveId,
string spdxIdPrefix,
string? description = null)
{
return new VulnerabilityElementBuilder(spdxIdPrefix)
.WithVulnerabilityId(cveId)
.WithDescription(description)
.WithNvdReference(cveId)
.Build();
}
private string GenerateSpdxId()
{
// Generate a deterministic SPDX ID from the vulnerability ID
using var sha = System.Security.Cryptography.SHA256.Create();
var input = _vulnerabilityId ?? string.Empty;
var hash = sha.ComputeHash(System.Text.Encoding.UTF8.GetBytes(input));
var shortHash = Convert.ToHexStringLower(hash)[..12];
return $"{_spdxIdPrefix.TrimEnd('/')}/vulnerability/{shortHash}";
}
}
/// <summary>
/// SPDX 3.0.1 External Identifier.
/// Sprint: SPRINT_20260107_004_004 Task SP-004
/// </summary>
public sealed record Spdx3ExternalIdentifier
{
/// <summary>
/// Gets or sets the external identifier type (e.g., "cve", "ghsa", "osv").
/// </summary>
public required string ExternalIdentifierType { get; init; }
/// <summary>
/// Gets or sets the identifier value.
/// </summary>
public required string Identifier { get; init; }
/// <summary>
/// Gets or sets the locator URLs for the identifier.
/// </summary>
public ImmutableArray<string> IdentifierLocator { get; init; } = ImmutableArray<string>.Empty;
/// <summary>
/// Gets or sets issuing authority of the identifier.
/// </summary>
public string? IssuingAuthority { get; init; }
}
/// <summary>
/// SPDX 3.0.1 External Reference.
/// Sprint: SPRINT_20260107_004_004 Task SP-004
/// </summary>
public sealed record Spdx3ExternalRef
{
/// <summary>
/// Gets or sets the external reference type (e.g., "securityAdvisory").
/// </summary>
public required string ExternalRefType { get; init; }
/// <summary>
/// Gets or sets the locator URLs.
/// </summary>
public ImmutableArray<string> Locator { get; init; } = ImmutableArray<string>.Empty;
/// <summary>
/// Gets or sets the content type of the referenced resource.
/// </summary>
public string? ContentType { get; init; }
/// <summary>
/// Gets or sets a comment about the reference.
/// </summary>
public string? Comment { get; init; }
}