339 lines
9.9 KiB
C#
339 lines
9.9 KiB
C#
using StellaOps.JobEngine.Core.Domain;
|
|
using StellaOps.JobEngine.Infrastructure.Repositories;
|
|
|
|
namespace StellaOps.JobEngine.WebService.Contracts;
|
|
|
|
// ===== Audit Contracts =====
|
|
|
|
/// <summary>
|
|
/// Response for an audit entry.
|
|
/// </summary>
|
|
public sealed record AuditEntryResponse(
|
|
Guid EntryId,
|
|
string TenantId,
|
|
string EventType,
|
|
string ResourceType,
|
|
Guid ResourceId,
|
|
string ActorId,
|
|
string ActorType,
|
|
string? ActorIp,
|
|
string? UserAgent,
|
|
string? HttpMethod,
|
|
string? RequestPath,
|
|
string? OldState,
|
|
string? NewState,
|
|
string Description,
|
|
string? CorrelationId,
|
|
string? PreviousEntryHash,
|
|
string ContentHash,
|
|
long SequenceNumber,
|
|
DateTimeOffset OccurredAt,
|
|
string? Metadata)
|
|
{
|
|
public static AuditEntryResponse FromDomain(AuditEntry entry) => new(
|
|
EntryId: entry.EntryId,
|
|
TenantId: entry.TenantId,
|
|
EventType: entry.EventType.ToString(),
|
|
ResourceType: entry.ResourceType,
|
|
ResourceId: entry.ResourceId,
|
|
ActorId: entry.ActorId,
|
|
ActorType: entry.ActorType.ToString(),
|
|
ActorIp: entry.ActorIp,
|
|
UserAgent: entry.UserAgent,
|
|
HttpMethod: entry.HttpMethod,
|
|
RequestPath: entry.RequestPath,
|
|
OldState: entry.OldState,
|
|
NewState: entry.NewState,
|
|
Description: entry.Description,
|
|
CorrelationId: entry.CorrelationId,
|
|
PreviousEntryHash: entry.PreviousEntryHash,
|
|
ContentHash: entry.ContentHash,
|
|
SequenceNumber: entry.SequenceNumber,
|
|
OccurredAt: entry.OccurredAt,
|
|
Metadata: entry.Metadata);
|
|
}
|
|
|
|
/// <summary>
|
|
/// List response for audit entries.
|
|
/// </summary>
|
|
public sealed record AuditEntryListResponse(
|
|
IReadOnlyList<AuditEntryResponse> Entries,
|
|
string? NextCursor);
|
|
|
|
/// <summary>
|
|
/// Response for audit summary.
|
|
/// </summary>
|
|
public sealed record AuditSummaryResponse(
|
|
long TotalEntries,
|
|
long EntriesSince,
|
|
long EventTypes,
|
|
long UniqueActors,
|
|
long UniqueResources,
|
|
DateTimeOffset? EarliestEntry,
|
|
DateTimeOffset? LatestEntry)
|
|
{
|
|
public static AuditSummaryResponse FromDomain(AuditSummary summary) => new(
|
|
TotalEntries: summary.TotalEntries,
|
|
EntriesSince: summary.EntriesSince,
|
|
EventTypes: summary.EventTypes,
|
|
UniqueActors: summary.UniqueActors,
|
|
UniqueResources: summary.UniqueResources,
|
|
EarliestEntry: summary.EarliestEntry,
|
|
LatestEntry: summary.LatestEntry);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Response for chain verification.
|
|
/// </summary>
|
|
public sealed record ChainVerificationResponse(
|
|
bool IsValid,
|
|
Guid? InvalidEntryId,
|
|
long? InvalidSequence,
|
|
string? ErrorMessage)
|
|
{
|
|
public static ChainVerificationResponse FromDomain(ChainVerificationResult result) => new(
|
|
IsValid: result.IsValid,
|
|
InvalidEntryId: result.InvalidEntryId,
|
|
InvalidSequence: result.InvalidSequence,
|
|
ErrorMessage: result.ErrorMessage);
|
|
}
|
|
|
|
// ===== Ledger Contracts =====
|
|
|
|
/// <summary>
|
|
/// Response for a ledger entry.
|
|
/// </summary>
|
|
public sealed record LedgerEntryResponse(
|
|
Guid LedgerId,
|
|
string TenantId,
|
|
Guid RunId,
|
|
Guid SourceId,
|
|
string RunType,
|
|
string FinalStatus,
|
|
int TotalJobs,
|
|
int SucceededJobs,
|
|
int FailedJobs,
|
|
DateTimeOffset RunCreatedAt,
|
|
DateTimeOffset? RunStartedAt,
|
|
DateTimeOffset RunCompletedAt,
|
|
long ExecutionDurationMs,
|
|
string InitiatedBy,
|
|
string InputDigest,
|
|
string OutputDigest,
|
|
long SequenceNumber,
|
|
string? PreviousEntryHash,
|
|
string ContentHash,
|
|
DateTimeOffset LedgerCreatedAt,
|
|
string? CorrelationId)
|
|
{
|
|
public static LedgerEntryResponse FromDomain(RunLedgerEntry entry) => new(
|
|
LedgerId: entry.LedgerId,
|
|
TenantId: entry.TenantId,
|
|
RunId: entry.RunId,
|
|
SourceId: entry.SourceId,
|
|
RunType: entry.RunType,
|
|
FinalStatus: entry.FinalStatus.ToString(),
|
|
TotalJobs: entry.TotalJobs,
|
|
SucceededJobs: entry.SucceededJobs,
|
|
FailedJobs: entry.FailedJobs,
|
|
RunCreatedAt: entry.RunCreatedAt,
|
|
RunStartedAt: entry.RunStartedAt,
|
|
RunCompletedAt: entry.RunCompletedAt,
|
|
ExecutionDurationMs: (long)entry.ExecutionDuration.TotalMilliseconds,
|
|
InitiatedBy: entry.InitiatedBy,
|
|
InputDigest: entry.InputDigest,
|
|
OutputDigest: entry.OutputDigest,
|
|
SequenceNumber: entry.SequenceNumber,
|
|
PreviousEntryHash: entry.PreviousEntryHash,
|
|
ContentHash: entry.ContentHash,
|
|
LedgerCreatedAt: entry.LedgerCreatedAt,
|
|
CorrelationId: entry.CorrelationId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// List response for ledger entries.
|
|
/// </summary>
|
|
public sealed record LedgerEntryListResponse(
|
|
IReadOnlyList<LedgerEntryResponse> Entries,
|
|
string? NextCursor);
|
|
|
|
/// <summary>
|
|
/// Response for ledger summary.
|
|
/// </summary>
|
|
public sealed record LedgerSummaryResponse(
|
|
long TotalEntries,
|
|
long EntriesSince,
|
|
long TotalRuns,
|
|
long SuccessfulRuns,
|
|
long FailedRuns,
|
|
long TotalJobs,
|
|
long UniqueSources,
|
|
long UniqueRunTypes,
|
|
DateTimeOffset? EarliestEntry,
|
|
DateTimeOffset? LatestEntry)
|
|
{
|
|
public static LedgerSummaryResponse FromDomain(LedgerSummary summary) => new(
|
|
TotalEntries: summary.TotalEntries,
|
|
EntriesSince: summary.EntriesSince,
|
|
TotalRuns: summary.TotalRuns,
|
|
SuccessfulRuns: summary.SuccessfulRuns,
|
|
FailedRuns: summary.FailedRuns,
|
|
TotalJobs: summary.TotalJobs,
|
|
UniqueSources: summary.UniqueSources,
|
|
UniqueRunTypes: summary.UniqueRunTypes,
|
|
EarliestEntry: summary.EarliestEntry,
|
|
LatestEntry: summary.LatestEntry);
|
|
}
|
|
|
|
// ===== Export Contracts =====
|
|
|
|
/// <summary>
|
|
/// Request to create a ledger export.
|
|
/// </summary>
|
|
public sealed record CreateLedgerExportRequest(
|
|
string Format,
|
|
DateTimeOffset? StartTime,
|
|
DateTimeOffset? EndTime,
|
|
string? RunTypeFilter,
|
|
Guid? SourceIdFilter);
|
|
|
|
/// <summary>
|
|
/// Response for a ledger export.
|
|
/// </summary>
|
|
public sealed record LedgerExportResponse(
|
|
Guid ExportId,
|
|
string TenantId,
|
|
string Status,
|
|
string Format,
|
|
DateTimeOffset? StartTime,
|
|
DateTimeOffset? EndTime,
|
|
string? RunTypeFilter,
|
|
Guid? SourceIdFilter,
|
|
int EntryCount,
|
|
string? OutputUri,
|
|
string? OutputDigest,
|
|
long? OutputSizeBytes,
|
|
string RequestedBy,
|
|
DateTimeOffset RequestedAt,
|
|
DateTimeOffset? StartedAt,
|
|
DateTimeOffset? CompletedAt,
|
|
string? ErrorMessage)
|
|
{
|
|
public static LedgerExportResponse FromDomain(LedgerExport export) => new(
|
|
ExportId: export.ExportId,
|
|
TenantId: export.TenantId,
|
|
Status: export.Status.ToString(),
|
|
Format: export.Format,
|
|
StartTime: export.StartTime,
|
|
EndTime: export.EndTime,
|
|
RunTypeFilter: export.RunTypeFilter,
|
|
SourceIdFilter: export.SourceIdFilter,
|
|
EntryCount: export.EntryCount,
|
|
OutputUri: export.OutputUri,
|
|
OutputDigest: export.OutputDigest,
|
|
OutputSizeBytes: export.OutputSizeBytes,
|
|
RequestedBy: export.RequestedBy,
|
|
RequestedAt: export.RequestedAt,
|
|
StartedAt: export.StartedAt,
|
|
CompletedAt: export.CompletedAt,
|
|
ErrorMessage: export.ErrorMessage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// List response for ledger exports.
|
|
/// </summary>
|
|
public sealed record LedgerExportListResponse(
|
|
IReadOnlyList<LedgerExportResponse> Exports,
|
|
string? NextCursor);
|
|
|
|
// ===== Manifest Contracts =====
|
|
|
|
/// <summary>
|
|
/// Response for a signed manifest.
|
|
/// </summary>
|
|
public sealed record ManifestResponse(
|
|
Guid ManifestId,
|
|
string SchemaVersion,
|
|
string TenantId,
|
|
string ProvenanceType,
|
|
Guid SubjectId,
|
|
string PayloadDigest,
|
|
string SignatureAlgorithm,
|
|
bool IsSigned,
|
|
bool IsExpired,
|
|
string KeyId,
|
|
DateTimeOffset CreatedAt,
|
|
DateTimeOffset? ExpiresAt)
|
|
{
|
|
public static ManifestResponse FromDomain(SignedManifest manifest) => new(
|
|
ManifestId: manifest.ManifestId,
|
|
SchemaVersion: manifest.SchemaVersion,
|
|
TenantId: manifest.TenantId,
|
|
ProvenanceType: manifest.ProvenanceType.ToString(),
|
|
SubjectId: manifest.SubjectId,
|
|
PayloadDigest: manifest.PayloadDigest,
|
|
SignatureAlgorithm: manifest.SignatureAlgorithm,
|
|
IsSigned: manifest.IsSigned,
|
|
IsExpired: manifest.IsExpired,
|
|
KeyId: manifest.KeyId,
|
|
CreatedAt: manifest.CreatedAt,
|
|
ExpiresAt: manifest.ExpiresAt);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Response with full manifest details including statements and artifacts.
|
|
/// </summary>
|
|
public sealed record ManifestDetailResponse(
|
|
Guid ManifestId,
|
|
string SchemaVersion,
|
|
string TenantId,
|
|
string ProvenanceType,
|
|
Guid SubjectId,
|
|
string Statements,
|
|
string Artifacts,
|
|
string Materials,
|
|
string? BuildInfo,
|
|
string PayloadDigest,
|
|
string SignatureAlgorithm,
|
|
string Signature,
|
|
string KeyId,
|
|
DateTimeOffset CreatedAt,
|
|
DateTimeOffset? ExpiresAt,
|
|
string? Metadata)
|
|
{
|
|
public static ManifestDetailResponse FromDomain(SignedManifest manifest) => new(
|
|
ManifestId: manifest.ManifestId,
|
|
SchemaVersion: manifest.SchemaVersion,
|
|
TenantId: manifest.TenantId,
|
|
ProvenanceType: manifest.ProvenanceType.ToString(),
|
|
SubjectId: manifest.SubjectId,
|
|
Statements: manifest.Statements,
|
|
Artifacts: manifest.Artifacts,
|
|
Materials: manifest.Materials,
|
|
BuildInfo: manifest.BuildInfo,
|
|
PayloadDigest: manifest.PayloadDigest,
|
|
SignatureAlgorithm: manifest.SignatureAlgorithm,
|
|
Signature: manifest.Signature,
|
|
KeyId: manifest.KeyId,
|
|
CreatedAt: manifest.CreatedAt,
|
|
ExpiresAt: manifest.ExpiresAt,
|
|
Metadata: manifest.Metadata);
|
|
}
|
|
|
|
/// <summary>
|
|
/// List response for manifests.
|
|
/// </summary>
|
|
public sealed record ManifestListResponse(
|
|
IReadOnlyList<ManifestResponse> Manifests,
|
|
string? NextCursor);
|
|
|
|
/// <summary>
|
|
/// Response for manifest verification.
|
|
/// </summary>
|
|
public sealed record ManifestVerificationResponse(
|
|
Guid ManifestId,
|
|
bool PayloadIntegrityValid,
|
|
bool IsExpired,
|
|
bool IsSigned,
|
|
string? ValidationError);
|