// -----------------------------------------------------------------------------
// IHumanApprovalAttestationService.cs
// Sprint: SPRINT_3801_0001_0004_human_approval_attestation (APPROVE-001)
// Description: Interface for creating human approval attestations.
// -----------------------------------------------------------------------------
using System.Threading;
using System.Threading.Tasks;
using StellaOps.Scanner.WebService.Contracts;
using StellaOps.Scanner.WebService.Domain;
namespace StellaOps.Scanner.WebService.Services;
///
/// Creates DSSE attestations for human approval decisions.
///
///
///
/// Human approvals record decisions made by authorized personnel to
/// accept, defer, reject, suppress, or escalate security findings.
///
///
/// These attestations have a 30-day default TTL to force periodic
/// re-review of risk acceptance decisions.
///
///
public interface IHumanApprovalAttestationService
{
///
/// Creates a human approval attestation.
///
/// The approval input parameters.
/// Cancellation token.
///
/// A containing the
/// attestation statement and content-addressed attestation ID.
///
Task CreateAttestationAsync(
HumanApprovalAttestationInput input,
CancellationToken cancellationToken = default);
///
/// Gets an existing approval attestation.
///
/// The scan ID.
/// The finding ID.
/// Cancellation token.
/// The attestation result if found, null otherwise.
Task GetAttestationAsync(
ScanId scanId,
string findingId,
CancellationToken cancellationToken = default);
///
/// Gets all active approval attestations for a scan.
///
/// The scan ID.
/// Cancellation token.
/// List of active approval attestations.
Task> GetApprovalsByScanAsync(
ScanId scanId,
CancellationToken cancellationToken = default);
///
/// Revokes an existing approval attestation.
///
/// The scan ID.
/// The finding ID.
/// Who revoked the approval.
/// Reason for revocation.
/// Cancellation token.
/// True if revoked, false if not found.
Task RevokeApprovalAsync(
ScanId scanId,
string findingId,
string revokedBy,
string reason,
CancellationToken cancellationToken = default);
}
///
/// Input for creating a human approval attestation.
///
public sealed record HumanApprovalAttestationInput
{
///
/// The scan ID.
///
public required ScanId ScanId { get; init; }
///
/// The finding ID (e.g., CVE identifier).
///
public required string FindingId { get; init; }
///
/// The approval decision.
///
public required ApprovalDecision Decision { get; init; }
///
/// The approver's user ID.
///
public required string ApproverUserId { get; init; }
///
/// The approver's display name.
///
public string? ApproverDisplayName { get; init; }
///
/// The approver's role.
///
public string? ApproverRole { get; init; }
///
/// Justification for the decision.
///
public required string Justification { get; init; }
///
/// Optional custom TTL for the approval.
///
public TimeSpan? ApprovalTtl { get; init; }
///
/// Reference to the policy decision attestation.
///
public string? PolicyDecisionRef { get; init; }
///
/// Optional restrictions on the approval scope.
///
public ApprovalRestrictions? Restrictions { get; init; }
///
/// Optional prior approval being superseded.
///
public string? Supersedes { get; init; }
///
/// Optional metadata.
///
public IDictionary? Metadata { get; init; }
}
///
/// Result of creating a human approval attestation.
///
public sealed record HumanApprovalAttestationResult
{
///
/// Whether the attestation was created successfully.
///
public required bool Success { get; init; }
///
/// The human approval statement.
///
public HumanApprovalStatement? Statement { get; init; }
///
/// The content-addressed attestation ID.
///
public string? AttestationId { get; init; }
///
/// The DSSE envelope (if signing is enabled).
///
public string? DsseEnvelope { get; init; }
///
/// Error message if creation failed.
///
public string? Error { get; init; }
///
/// Whether the approval has been revoked.
///
public bool IsRevoked { get; init; }
///
/// Creates a successful result.
///
public static HumanApprovalAttestationResult Succeeded(
HumanApprovalStatement statement,
string attestationId,
string? dsseEnvelope = null)
=> new()
{
Success = true,
Statement = statement,
AttestationId = attestationId,
DsseEnvelope = dsseEnvelope
};
///
/// Creates a failed result.
///
public static HumanApprovalAttestationResult Failed(string error)
=> new()
{
Success = false,
Error = error
};
}