stabilizaiton work - projects rework for maintenanceability and ui livening

This commit is contained in:
master
2026-02-03 23:40:04 +02:00
parent 074ce117ba
commit 557feefdc3
3305 changed files with 186813 additions and 107843 deletions

View File

@@ -1,5 +1,4 @@
using System.Security.Cryptography;
using System.Text;
using System;
namespace StellaOps.Provcache;
@@ -23,7 +22,7 @@ namespace StellaOps.Provcache;
/// </list>
/// </para>
/// </remarks>
public sealed class VeriKeyBuilder
public sealed partial class VeriKeyBuilder
{
private string? _sourceHash;
private string? _sbomHash;
@@ -48,342 +47,4 @@ public sealed class VeriKeyBuilder
{
_options = options ?? throw new ArgumentNullException(nameof(options));
}
/// <summary>
/// Sets the source artifact digest (image/artifact content-addressed hash).
/// </summary>
/// <param name="sourceHash">The artifact digest (e.g., sha256:abc123...).</param>
/// <returns>This builder for fluent chaining.</returns>
/// <exception cref="ArgumentException">If sourceHash is null or empty.</exception>
public VeriKeyBuilder WithSourceHash(string sourceHash)
{
if (string.IsNullOrWhiteSpace(sourceHash))
throw new ArgumentException("Source hash cannot be null or empty.", nameof(sourceHash));
_sourceHash = NormalizeHash(sourceHash);
return this;
}
/// <summary>
/// Sets the SBOM canonical hash.
/// Automatically canonicalizes the SBOM content before hashing if raw bytes are provided.
/// </summary>
/// <param name="sbomHash">The SBOM canonical hash.</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithSbomHash(string sbomHash)
{
if (string.IsNullOrWhiteSpace(sbomHash))
throw new ArgumentException("SBOM hash cannot be null or empty.", nameof(sbomHash));
_sbomHash = NormalizeHash(sbomHash);
return this;
}
/// <summary>
/// Computes SBOM hash from raw SBOM bytes using canonical serialization.
/// </summary>
/// <param name="sbomBytes">Raw SBOM content bytes.</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithSbomBytes(ReadOnlySpan<byte> sbomBytes)
{
_sbomHash = ComputeHash(sbomBytes);
return this;
}
/// <summary>
/// Sets the VEX hash set hash (sorted aggregation of VEX statement hashes).
/// </summary>
/// <param name="vexHashSetHash">The pre-computed VEX hash set hash.</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithVexHashSet(string vexHashSetHash)
{
if (string.IsNullOrWhiteSpace(vexHashSetHash))
throw new ArgumentException("VEX hash set hash cannot be null or empty.", nameof(vexHashSetHash));
_vexHashSetHash = NormalizeHash(vexHashSetHash);
return this;
}
/// <summary>
/// Computes VEX hash set from individual VEX statement hashes.
/// Hashes are sorted lexicographically before aggregation for determinism.
/// </summary>
/// <param name="vexStatementHashes">Individual VEX statement hashes.</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithVexStatementHashes(IEnumerable<string> vexStatementHashes)
{
ArgumentNullException.ThrowIfNull(vexStatementHashes);
// Sort hashes for deterministic aggregation
var sortedHashes = vexStatementHashes
.Where(h => !string.IsNullOrWhiteSpace(h))
.Select(NormalizeHash)
.Order(StringComparer.Ordinal)
.ToList();
if (sortedHashes.Count == 0)
{
// Empty VEX set gets a well-known hash
_vexHashSetHash = ComputeHash(Encoding.UTF8.GetBytes("empty-vex-set"));
}
else
{
// Concatenate sorted hashes and hash the result
var concatenated = string.Join("|", sortedHashes);
_vexHashSetHash = ComputeHash(Encoding.UTF8.GetBytes(concatenated));
}
return this;
}
/// <summary>
/// Sets the merge policy hash (PolicyBundle digest).
/// </summary>
/// <param name="policyHash">The policy bundle hash.</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithMergePolicyHash(string policyHash)
{
if (string.IsNullOrWhiteSpace(policyHash))
throw new ArgumentException("Policy hash cannot be null or empty.", nameof(policyHash));
_mergePolicyHash = NormalizeHash(policyHash);
return this;
}
/// <summary>
/// Computes policy hash from raw policy bundle bytes.
/// </summary>
/// <param name="policyBytes">Raw policy bundle content bytes.</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithMergePolicyBytes(ReadOnlySpan<byte> policyBytes)
{
_mergePolicyHash = ComputeHash(policyBytes);
return this;
}
/// <summary>
/// Sets the signer set hash (sorted certificate chain hashes).
/// </summary>
/// <param name="signerSetHash">The pre-computed signer set hash.</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithSignerSetHash(string signerSetHash)
{
if (string.IsNullOrWhiteSpace(signerSetHash))
throw new ArgumentException("Signer set hash cannot be null or empty.", nameof(signerSetHash));
_signerSetHash = NormalizeHash(signerSetHash);
return this;
}
/// <summary>
/// Computes signer set hash from individual certificate hashes.
/// Hashes are sorted lexicographically before aggregation for determinism.
/// </summary>
/// <param name="certificateHashes">Individual certificate hashes.</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithCertificateHashes(IEnumerable<string> certificateHashes)
{
ArgumentNullException.ThrowIfNull(certificateHashes);
// Sort hashes for deterministic aggregation
var sortedHashes = certificateHashes
.Where(h => !string.IsNullOrWhiteSpace(h))
.Select(NormalizeHash)
.Order(StringComparer.Ordinal)
.ToList();
if (sortedHashes.Count == 0)
{
// Empty signer set gets a well-known hash
_signerSetHash = ComputeHash(Encoding.UTF8.GetBytes("empty-signer-set"));
}
else
{
// Concatenate sorted hashes and hash the result
var concatenated = string.Join("|", sortedHashes);
_signerSetHash = ComputeHash(Encoding.UTF8.GetBytes(concatenated));
}
return this;
}
/// <summary>
/// Sets the time window for epoch bucketing.
/// </summary>
/// <param name="timeWindow">The time window identifier (e.g., "2024-12-24T12:00:00Z").</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithTimeWindow(string timeWindow)
{
if (string.IsNullOrWhiteSpace(timeWindow))
throw new ArgumentException("Time window cannot be null or empty.", nameof(timeWindow));
_timeWindow = timeWindow;
return this;
}
/// <summary>
/// Computes time window from a timestamp using the configured bucket size.
/// </summary>
/// <param name="timestamp">The timestamp to bucket.</param>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder WithTimeWindow(DateTimeOffset timestamp)
{
_timeWindow = _options.ComputeTimeWindow(timestamp);
return this;
}
/// <summary>
/// Builds the final VeriKey by hashing all components together.
/// </summary>
/// <returns>The computed VeriKey in format "sha256:&lt;hex&gt;".</returns>
/// <exception cref="InvalidOperationException">If required components are missing.</exception>
public string Build()
{
ValidateRequiredComponents();
// Build composite hash input: all components concatenated with delimiters
var components = new StringBuilder();
components.Append("v1|"); // Version prefix for future compatibility
components.Append(_sourceHash);
components.Append('|');
components.Append(_sbomHash);
components.Append('|');
components.Append(_vexHashSetHash);
components.Append('|');
components.Append(_mergePolicyHash);
components.Append('|');
components.Append(_signerSetHash);
components.Append('|');
components.Append(_timeWindow);
var compositeBytes = Encoding.UTF8.GetBytes(components.ToString());
return ComputeHash(compositeBytes);
}
/// <summary>
/// Builds a <see cref="VeriKeyComponents"/> record with all individual components.
/// Useful for debugging and serialization.
/// </summary>
/// <returns>A record containing all VeriKey components.</returns>
public VeriKeyComponents BuildWithComponents()
{
ValidateRequiredComponents();
return new VeriKeyComponents
{
VeriKey = Build(),
SourceHash = _sourceHash!,
SbomHash = _sbomHash!,
VexHashSetHash = _vexHashSetHash!,
MergePolicyHash = _mergePolicyHash!,
SignerSetHash = _signerSetHash!,
TimeWindow = _timeWindow!
};
}
/// <summary>
/// Resets the builder to its initial state.
/// </summary>
/// <returns>This builder for fluent chaining.</returns>
public VeriKeyBuilder Reset()
{
_sourceHash = null;
_sbomHash = null;
_vexHashSetHash = null;
_mergePolicyHash = null;
_signerSetHash = null;
_timeWindow = null;
return this;
}
private void ValidateRequiredComponents()
{
var missing = new List<string>();
if (string.IsNullOrWhiteSpace(_sourceHash))
missing.Add("SourceHash");
if (string.IsNullOrWhiteSpace(_sbomHash))
missing.Add("SbomHash");
if (string.IsNullOrWhiteSpace(_vexHashSetHash))
missing.Add("VexHashSetHash");
if (string.IsNullOrWhiteSpace(_mergePolicyHash))
missing.Add("MergePolicyHash");
if (string.IsNullOrWhiteSpace(_signerSetHash))
missing.Add("SignerSetHash");
if (string.IsNullOrWhiteSpace(_timeWindow))
missing.Add("TimeWindow");
if (missing.Count > 0)
{
throw new InvalidOperationException(
$"Cannot build VeriKey: missing required components: {string.Join(", ", missing)}. " +
"Use the With* methods to set all required components before calling Build().");
}
}
private static string ComputeHash(ReadOnlySpan<byte> data)
{
Span<byte> hash = stackalloc byte[32];
SHA256.HashData(data, hash);
return $"sha256:{Convert.ToHexStringLower(hash)}";
}
private static string NormalizeHash(string hash)
{
// If hash already has algorithm prefix, validate and return lowercase
if (hash.StartsWith("sha256:", StringComparison.OrdinalIgnoreCase))
{
return $"sha256:{hash[7..].ToLowerInvariant()}";
}
// Assume SHA256 if no prefix and looks like a hex string
if (hash.Length == 64 && hash.All(c => char.IsAsciiHexDigit(c)))
{
return $"sha256:{hash.ToLowerInvariant()}";
}
// Return as-is if not recognized (might be other hash format)
return hash.ToLowerInvariant();
}
}
/// <summary>
/// Record containing all VeriKey components for debugging and serialization.
/// </summary>
public sealed record VeriKeyComponents
{
/// <summary>
/// The final computed VeriKey.
/// </summary>
public required string VeriKey { get; init; }
/// <summary>
/// Source artifact digest.
/// </summary>
public required string SourceHash { get; init; }
/// <summary>
/// SBOM canonical hash.
/// </summary>
public required string SbomHash { get; init; }
/// <summary>
/// VEX hash set hash.
/// </summary>
public required string VexHashSetHash { get; init; }
/// <summary>
/// Policy bundle hash.
/// </summary>
public required string MergePolicyHash { get; init; }
/// <summary>
/// Signer certificate set hash.
/// </summary>
public required string SignerSetHash { get; init; }
/// <summary>
/// Time window identifier.
/// </summary>
public required string TimeWindow { get; init; }
}