save progress
This commit is contained in:
114
src/__Libraries/StellaOps.Facet/FacetSeal.cs
Normal file
114
src/__Libraries/StellaOps.Facet/FacetSeal.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
// <copyright file="FacetSeal.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace StellaOps.Facet;
|
||||
|
||||
/// <summary>
|
||||
/// Sealed manifest of facets for an image at a point in time.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A FacetSeal captures the cryptographic state of all facets in an image,
|
||||
/// enabling drift detection and quota enforcement on subsequent scans.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The seal can be optionally signed with DSSE for authenticity verification.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public sealed record FacetSeal
|
||||
{
|
||||
/// <summary>
|
||||
/// Current schema version.
|
||||
/// </summary>
|
||||
public const string CurrentSchemaVersion = "1.0.0";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the schema version for forward compatibility.
|
||||
/// </summary>
|
||||
public string SchemaVersion { get; init; } = CurrentSchemaVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image digest this seal applies to.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Format: "sha256:{hex}" or "sha512:{hex}".
|
||||
/// </remarks>
|
||||
public required string ImageDigest { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets when the seal was created.
|
||||
/// </summary>
|
||||
public required DateTimeOffset CreatedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the optional build attestation reference (in-toto provenance).
|
||||
/// </summary>
|
||||
public string? BuildAttestationRef { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the individual facet seals.
|
||||
/// </summary>
|
||||
public required ImmutableArray<FacetEntry> Facets { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quota configuration per facet.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Keys are facet IDs. Facets without explicit quotas use default values.
|
||||
/// </remarks>
|
||||
public ImmutableDictionary<string, FacetQuota>? Quotas { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the combined Merkle root of all facet roots.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Computed from facet Merkle roots in sorted order by FacetId.
|
||||
/// Enables single-value integrity verification.
|
||||
/// </remarks>
|
||||
public required string CombinedMerkleRoot { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the optional DSSE signature over canonical form.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Base64-encoded DSSE envelope when the seal is signed.
|
||||
/// </remarks>
|
||||
public string? Signature { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the signing key identifier, if signed.
|
||||
/// </summary>
|
||||
public string? SigningKeyId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this seal is signed.
|
||||
/// </summary>
|
||||
public bool IsSigned => !string.IsNullOrEmpty(Signature);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quota for a specific facet, or default if not configured.
|
||||
/// </summary>
|
||||
/// <param name="facetId">The facet identifier.</param>
|
||||
/// <returns>The configured quota or <see cref="FacetQuota.Default"/>.</returns>
|
||||
public FacetQuota GetQuota(string facetId)
|
||||
{
|
||||
if (Quotas is not null &&
|
||||
Quotas.TryGetValue(facetId, out var quota))
|
||||
{
|
||||
return quota;
|
||||
}
|
||||
|
||||
return FacetQuota.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a facet entry by ID.
|
||||
/// </summary>
|
||||
/// <param name="facetId">The facet identifier.</param>
|
||||
/// <returns>The facet entry or null if not found.</returns>
|
||||
public FacetEntry? GetFacet(string facetId)
|
||||
=> Facets.FirstOrDefault(f => f.FacetId == facetId);
|
||||
}
|
||||
Reference in New Issue
Block a user