sprints and audit work
This commit is contained in:
109
src/__Libraries/StellaOps.Facet/IFacetSealStore.cs
Normal file
109
src/__Libraries/StellaOps.Facet/IFacetSealStore.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
// <copyright file="IFacetSealStore.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace StellaOps.Facet;
|
||||
|
||||
/// <summary>
|
||||
/// Persistent store for <see cref="FacetSeal"/> instances.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Implementations provide storage and retrieval of facet seals for drift detection
|
||||
/// and quota enforcement. Seals are indexed by image digest and creation time.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Sprint: SPRINT_20260105_002_003_FACET (QTA-012)
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public interface IFacetSealStore
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the most recent seal for an image digest.
|
||||
/// </summary>
|
||||
/// <param name="imageDigest">The image digest (e.g., "sha256:{hex}").</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>The latest seal, or null if no seal exists for this image.</returns>
|
||||
Task<FacetSeal?> GetLatestSealAsync(string imageDigest, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get a seal by its combined Merkle root (unique identifier).
|
||||
/// </summary>
|
||||
/// <param name="combinedMerkleRoot">The seal's combined Merkle root.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>The seal, or null if not found.</returns>
|
||||
Task<FacetSeal?> GetByCombinedRootAsync(string combinedMerkleRoot, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get seal history for an image digest.
|
||||
/// </summary>
|
||||
/// <param name="imageDigest">The image digest.</param>
|
||||
/// <param name="limit">Maximum number of seals to return.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Seals in descending order by creation time (most recent first).</returns>
|
||||
Task<ImmutableArray<FacetSeal>> GetHistoryAsync(
|
||||
string imageDigest,
|
||||
int limit = 10,
|
||||
CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Save a seal to the store.
|
||||
/// </summary>
|
||||
/// <param name="seal">The seal to save.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>A task representing the async operation.</returns>
|
||||
/// <exception cref="ArgumentNullException">If seal is null.</exception>
|
||||
/// <exception cref="SealAlreadyExistsException">If a seal with the same combined root exists.</exception>
|
||||
Task SaveAsync(FacetSeal seal, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Check if a seal exists for an image digest.
|
||||
/// </summary>
|
||||
/// <param name="imageDigest">The image digest.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>True if at least one seal exists.</returns>
|
||||
Task<bool> ExistsAsync(string imageDigest, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Delete all seals for an image digest.
|
||||
/// </summary>
|
||||
/// <param name="imageDigest">The image digest.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Number of seals deleted.</returns>
|
||||
Task<int> DeleteByImageAsync(string imageDigest, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Purge seals older than the specified retention period.
|
||||
/// </summary>
|
||||
/// <param name="retentionPeriod">Retention period from creation time.</param>
|
||||
/// <param name="keepAtLeast">Minimum seals to keep per image digest.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Number of seals purged.</returns>
|
||||
Task<int> PurgeOldSealsAsync(
|
||||
TimeSpan retentionPeriod,
|
||||
int keepAtLeast = 1,
|
||||
CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception thrown when attempting to save a duplicate seal.
|
||||
/// </summary>
|
||||
public sealed class SealAlreadyExistsException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SealAlreadyExistsException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="combinedMerkleRoot">The duplicate seal's combined root.</param>
|
||||
public SealAlreadyExistsException(string combinedMerkleRoot)
|
||||
: base($"A seal with combined Merkle root '{combinedMerkleRoot}' already exists.")
|
||||
{
|
||||
CombinedMerkleRoot = combinedMerkleRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duplicate seal's combined Merkle root.
|
||||
/// </summary>
|
||||
public string CombinedMerkleRoot { get; }
|
||||
}
|
||||
Reference in New Issue
Block a user