using StellaOps.Policy.Registry.Contracts;
namespace StellaOps.Policy.Registry.Services;
///
/// Service for managing policy pack review workflows with audit trails.
/// Implements REGISTRY-API-27-006: Review workflow with audit trails.
///
public interface IReviewWorkflowService
{
///
/// Submits a policy pack for review.
///
Task SubmitForReviewAsync(
Guid tenantId,
Guid packId,
SubmitReviewRequest request,
CancellationToken cancellationToken = default);
///
/// Approves a review request.
///
Task ApproveAsync(
Guid tenantId,
string reviewId,
ApproveReviewRequest request,
CancellationToken cancellationToken = default);
///
/// Rejects a review request.
///
Task RejectAsync(
Guid tenantId,
string reviewId,
RejectReviewRequest request,
CancellationToken cancellationToken = default);
///
/// Requests changes to a policy pack under review.
///
Task RequestChangesAsync(
Guid tenantId,
string reviewId,
RequestChangesRequest request,
CancellationToken cancellationToken = default);
///
/// Gets a review request by ID.
///
Task GetReviewAsync(
Guid tenantId,
string reviewId,
CancellationToken cancellationToken = default);
///
/// Lists review requests for a tenant.
///
Task ListReviewsAsync(
Guid tenantId,
ReviewStatus? status = null,
Guid? packId = null,
int pageSize = 20,
string? pageToken = null,
CancellationToken cancellationToken = default);
///
/// Gets the audit trail for a review.
///
Task> GetAuditTrailAsync(
Guid tenantId,
string reviewId,
CancellationToken cancellationToken = default);
///
/// Gets the audit trail for a policy pack across all reviews.
///
Task> GetPackAuditTrailAsync(
Guid tenantId,
Guid packId,
int limit = 100,
CancellationToken cancellationToken = default);
}
///
/// Request to submit a policy pack for review.
///
public sealed record SubmitReviewRequest
{
public string? Description { get; init; }
public IReadOnlyList? Reviewers { get; init; }
public ReviewUrgency Urgency { get; init; } = ReviewUrgency.Normal;
public IReadOnlyDictionary? Metadata { get; init; }
}
///
/// Request to approve a review.
///
public sealed record ApproveReviewRequest
{
public string? Comment { get; init; }
public string? ApprovedBy { get; init; }
}
///
/// Request to reject a review.
///
public sealed record RejectReviewRequest
{
public required string Reason { get; init; }
public string? RejectedBy { get; init; }
}
///
/// Request to request changes.
///
public sealed record RequestChangesRequest
{
public required IReadOnlyList Comments { get; init; }
public string? RequestedBy { get; init; }
}
///
/// Review comment.
///
public sealed record ReviewComment
{
public string? RuleId { get; init; }
public required string Comment { get; init; }
public ReviewCommentSeverity Severity { get; init; } = ReviewCommentSeverity.Suggestion;
}
///
/// Review comment severity.
///
public enum ReviewCommentSeverity
{
Suggestion,
Warning,
Blocking
}
///
/// Review urgency level.
///
public enum ReviewUrgency
{
Low,
Normal,
High,
Critical
}
///
/// Review request status.
///
public enum ReviewStatus
{
Pending,
InReview,
ChangesRequested,
Approved,
Rejected,
Cancelled
}
///
/// Review request.
///
public sealed record ReviewRequest
{
public required string ReviewId { get; init; }
public required Guid TenantId { get; init; }
public required Guid PackId { get; init; }
public required string PackVersion { get; init; }
public required ReviewStatus Status { get; init; }
public string? Description { get; init; }
public IReadOnlyList? Reviewers { get; init; }
public ReviewUrgency Urgency { get; init; }
public string? SubmittedBy { get; init; }
public required DateTimeOffset SubmittedAt { get; init; }
public DateTimeOffset? ResolvedAt { get; init; }
public string? ResolvedBy { get; init; }
public IReadOnlyList? PendingComments { get; init; }
public IReadOnlyDictionary? Metadata { get; init; }
}
///
/// Review decision result.
///
public sealed record ReviewDecision
{
public required string ReviewId { get; init; }
public required ReviewStatus NewStatus { get; init; }
public required DateTimeOffset DecidedAt { get; init; }
public string? DecidedBy { get; init; }
public string? Comment { get; init; }
public IReadOnlyList? Comments { get; init; }
}
///
/// List of review requests.
///
public sealed record ReviewRequestList
{
public required IReadOnlyList Items { get; init; }
public string? NextPageToken { get; init; }
public int TotalCount { get; init; }
}
///
/// Audit entry for review actions.
///
public sealed record ReviewAuditEntry
{
public required string AuditId { get; init; }
public required string ReviewId { get; init; }
public required Guid PackId { get; init; }
public required ReviewAuditAction Action { get; init; }
public required DateTimeOffset Timestamp { get; init; }
public string? PerformedBy { get; init; }
public ReviewStatus? PreviousStatus { get; init; }
public ReviewStatus? NewStatus { get; init; }
public string? Comment { get; init; }
public IReadOnlyDictionary? Details { get; init; }
}
///
/// Review audit action types.
///
public enum ReviewAuditAction
{
Submitted,
AssignedReviewer,
RemovedReviewer,
CommentAdded,
ChangesRequested,
Approved,
Rejected,
Cancelled,
Reopened,
StatusChanged
}