Files
git.stella-ops.org/src/Cli/StellaOps.Cli/Services/Models/PolicyWorkspaceModels.cs
master 75f6942769
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Add integration tests for migration categories and execution
- Implemented MigrationCategoryTests to validate migration categorization for startup, release, seed, and data migrations.
- Added tests for edge cases, including null, empty, and whitespace migration names.
- Created StartupMigrationHostTests to verify the behavior of the migration host with real PostgreSQL instances using Testcontainers.
- Included tests for migration execution, schema creation, and handling of pending release migrations.
- Added SQL migration files for testing: creating a test table, adding a column, a release migration, and seeding data.
2025-12-04 19:10:54 +02:00

1203 lines
31 KiB
C#

using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace StellaOps.Cli.Services.Models;
// CLI-POLICY-20-001: Policy scaffolding and workspace models
/// <summary>
/// Available policy templates.
/// </summary>
internal enum PolicyTemplate
{
/// <summary>
/// Minimal policy with basic structure.
/// </summary>
Minimal,
/// <summary>
/// Baseline severity normalization template.
/// </summary>
Baseline,
/// <summary>
/// VEX precedence handling template.
/// </summary>
VexPrecedence,
/// <summary>
/// Reachability-aware policy template.
/// </summary>
Reachability,
/// <summary>
/// Secret leak detection template.
/// </summary>
SecretLeak,
/// <summary>
/// Full-featured template with all sections.
/// </summary>
Full
}
/// <summary>
/// Request for creating a new policy from template.
/// </summary>
internal sealed class PolicyNewRequest
{
[JsonPropertyName("name")]
public string Name { get; init; } = string.Empty;
[JsonPropertyName("template")]
public PolicyTemplate Template { get; init; } = PolicyTemplate.Minimal;
[JsonPropertyName("outputPath")]
public string? OutputPath { get; init; }
[JsonPropertyName("description")]
public string? Description { get; init; }
[JsonPropertyName("tags")]
public IReadOnlyList<string>? Tags { get; init; }
[JsonPropertyName("syntaxVersion")]
public string SyntaxVersion { get; init; } = "stella-dsl@1";
[JsonPropertyName("shadowMode")]
public bool ShadowMode { get; init; } = true;
[JsonPropertyName("createFixtures")]
public bool CreateFixtures { get; init; }
[JsonPropertyName("gitInit")]
public bool GitInit { get; init; }
}
/// <summary>
/// Result of policy scaffolding.
/// </summary>
internal sealed class PolicyNewResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("policyPath")]
public string PolicyPath { get; init; } = string.Empty;
[JsonPropertyName("fixturesPath")]
public string? FixturesPath { get; init; }
[JsonPropertyName("template")]
public string Template { get; init; } = string.Empty;
[JsonPropertyName("syntaxVersion")]
public string SyntaxVersion { get; init; } = string.Empty;
[JsonPropertyName("errors")]
public IReadOnlyList<string>? Errors { get; init; }
[JsonPropertyName("warnings")]
public IReadOnlyList<string>? Warnings { get; init; }
}
// CLI-POLICY-23-006: Policy history and explain models
/// <summary>
/// Request for policy run history.
/// </summary>
internal sealed class PolicyHistoryRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
[JsonPropertyName("from")]
public DateTimeOffset? From { get; init; }
[JsonPropertyName("to")]
public DateTimeOffset? To { get; init; }
[JsonPropertyName("status")]
public string? Status { get; init; }
[JsonPropertyName("limit")]
public int? Limit { get; init; }
[JsonPropertyName("cursor")]
public string? Cursor { get; init; }
}
/// <summary>
/// Policy run history response.
/// </summary>
internal sealed class PolicyHistoryResponse
{
[JsonPropertyName("items")]
public IReadOnlyList<PolicyRunSummary> Items { get; init; } = [];
[JsonPropertyName("total")]
public int Total { get; init; }
[JsonPropertyName("hasMore")]
public bool HasMore { get; init; }
[JsonPropertyName("nextCursor")]
public string? NextCursor { get; init; }
}
/// <summary>
/// Summary of a policy run.
/// </summary>
internal sealed class PolicyRunSummary
{
[JsonPropertyName("runId")]
public string RunId { get; init; } = string.Empty;
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("policyVersion")]
public int PolicyVersion { get; init; }
[JsonPropertyName("status")]
public string Status { get; init; } = string.Empty;
[JsonPropertyName("startedAt")]
public DateTimeOffset StartedAt { get; init; }
[JsonPropertyName("completedAt")]
public DateTimeOffset? CompletedAt { get; init; }
[JsonPropertyName("duration")]
public TimeSpan? Duration { get; init; }
[JsonPropertyName("sbomCount")]
public int SbomCount { get; init; }
[JsonPropertyName("findingsGenerated")]
public int FindingsGenerated { get; init; }
[JsonPropertyName("findingsChanged")]
public int FindingsChanged { get; init; }
[JsonPropertyName("triggeredBy")]
public string? TriggeredBy { get; init; }
[JsonPropertyName("correlationId")]
public string? CorrelationId { get; init; }
}
/// <summary>
/// Request for policy explain tree.
/// </summary>
internal sealed class PolicyExplainRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("runId")]
public string? RunId { get; init; }
[JsonPropertyName("findingId")]
public string? FindingId { get; init; }
[JsonPropertyName("sbomId")]
public string? SbomId { get; init; }
[JsonPropertyName("componentPurl")]
public string? ComponentPurl { get; init; }
[JsonPropertyName("advisoryId")]
public string? AdvisoryId { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
[JsonPropertyName("depth")]
public int? Depth { get; init; }
}
/// <summary>
/// Policy explain result with decision tree.
/// </summary>
internal sealed class PolicyExplainResult
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("policyVersion")]
public int PolicyVersion { get; init; }
[JsonPropertyName("runId")]
public string? RunId { get; init; }
[JsonPropertyName("timestamp")]
public DateTimeOffset Timestamp { get; init; }
[JsonPropertyName("subject")]
public PolicyExplainSubject? Subject { get; init; }
[JsonPropertyName("decision")]
public PolicyDecision? Decision { get; init; }
[JsonPropertyName("ruleTrace")]
public IReadOnlyList<PolicyRuleTraceEntry>? RuleTrace { get; init; }
[JsonPropertyName("inputContext")]
public PolicyInputContext? InputContext { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string>? Errors { get; init; }
}
/// <summary>
/// Subject being explained (component + advisory).
/// </summary>
internal sealed class PolicyExplainSubject
{
[JsonPropertyName("componentPurl")]
public string? ComponentPurl { get; init; }
[JsonPropertyName("componentName")]
public string? ComponentName { get; init; }
[JsonPropertyName("componentVersion")]
public string? ComponentVersion { get; init; }
[JsonPropertyName("advisoryId")]
public string? AdvisoryId { get; init; }
[JsonPropertyName("advisorySource")]
public string? AdvisorySource { get; init; }
[JsonPropertyName("sbomId")]
public string? SbomId { get; init; }
}
/// <summary>
/// Policy decision outcome.
/// </summary>
internal sealed class PolicyDecision
{
[JsonPropertyName("status")]
public string Status { get; init; } = string.Empty;
[JsonPropertyName("severity")]
public string? Severity { get; init; }
[JsonPropertyName("severityScore")]
public double? SeverityScore { get; init; }
[JsonPropertyName("winningRule")]
public string? WinningRule { get; init; }
[JsonPropertyName("rationale")]
public string? Rationale { get; init; }
[JsonPropertyName("annotations")]
public IReadOnlyDictionary<string, string>? Annotations { get; init; }
}
/// <summary>
/// Entry in the rule evaluation trace.
/// </summary>
internal sealed class PolicyRuleTraceEntry
{
[JsonPropertyName("ruleName")]
public string RuleName { get; init; } = string.Empty;
[JsonPropertyName("priority")]
public int Priority { get; init; }
[JsonPropertyName("evaluated")]
public bool Evaluated { get; init; }
[JsonPropertyName("matched")]
public bool Matched { get; init; }
[JsonPropertyName("predicates")]
public IReadOnlyList<PolicyPredicateEvaluation>? Predicates { get; init; }
[JsonPropertyName("actions")]
public IReadOnlyList<PolicyActionResult>? Actions { get; init; }
[JsonPropertyName("because")]
public string? Because { get; init; }
[JsonPropertyName("skippedReason")]
public string? SkippedReason { get; init; }
}
/// <summary>
/// Predicate evaluation result.
/// </summary>
internal sealed class PolicyPredicateEvaluation
{
[JsonPropertyName("expression")]
public string Expression { get; init; } = string.Empty;
[JsonPropertyName("result")]
public bool Result { get; init; }
[JsonPropertyName("leftValue")]
public string? LeftValue { get; init; }
[JsonPropertyName("rightValue")]
public string? RightValue { get; init; }
}
/// <summary>
/// Action execution result.
/// </summary>
internal sealed class PolicyActionResult
{
[JsonPropertyName("action")]
public string Action { get; init; } = string.Empty;
[JsonPropertyName("target")]
public string? Target { get; init; }
[JsonPropertyName("value")]
public string? Value { get; init; }
[JsonPropertyName("executed")]
public bool Executed { get; init; }
}
/// <summary>
/// Input context used for evaluation.
/// </summary>
internal sealed class PolicyInputContext
{
[JsonPropertyName("sbom")]
public IReadOnlyDictionary<string, object?>? Sbom { get; init; }
[JsonPropertyName("advisory")]
public IReadOnlyDictionary<string, object?>? Advisory { get; init; }
[JsonPropertyName("vex")]
public IReadOnlyList<IReadOnlyDictionary<string, object?>>? Vex { get; init; }
[JsonPropertyName("env")]
public IReadOnlyDictionary<string, string?>? Env { get; init; }
[JsonPropertyName("telemetry")]
public IReadOnlyDictionary<string, object?>? Telemetry { get; init; }
[JsonPropertyName("signals")]
public IReadOnlyDictionary<string, object?>? Signals { get; init; }
}
// CLI-POLICY-27-001: Policy workspace models
/// <summary>
/// Request to initialize a policy workspace.
/// </summary>
internal sealed class PolicyWorkspaceInitRequest
{
[JsonPropertyName("path")]
public string Path { get; init; } = string.Empty;
[JsonPropertyName("name")]
public string? Name { get; init; }
[JsonPropertyName("template")]
public PolicyTemplate Template { get; init; } = PolicyTemplate.Minimal;
[JsonPropertyName("gitInit")]
public bool GitInit { get; init; } = true;
[JsonPropertyName("createReadme")]
public bool CreateReadme { get; init; } = true;
[JsonPropertyName("createFixtures")]
public bool CreateFixtures { get; init; } = true;
}
/// <summary>
/// Result of workspace initialization.
/// </summary>
internal sealed class PolicyWorkspaceInitResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("workspacePath")]
public string WorkspacePath { get; init; } = string.Empty;
[JsonPropertyName("policyPath")]
public string? PolicyPath { get; init; }
[JsonPropertyName("fixturesPath")]
public string? FixturesPath { get; init; }
[JsonPropertyName("gitInitialized")]
public bool GitInitialized { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string>? Errors { get; init; }
[JsonPropertyName("warnings")]
public IReadOnlyList<string>? Warnings { get; init; }
}
/// <summary>
/// Request to compile a policy DSL file.
/// </summary>
internal sealed class PolicyCompileRequest
{
[JsonPropertyName("inputPath")]
public string InputPath { get; init; } = string.Empty;
[JsonPropertyName("outputPath")]
public string? OutputPath { get; init; }
[JsonPropertyName("emitIr")]
public bool EmitIr { get; init; } = true;
[JsonPropertyName("emitDigest")]
public bool EmitDigest { get; init; } = true;
[JsonPropertyName("optimize")]
public bool Optimize { get; init; }
[JsonPropertyName("strict")]
public bool Strict { get; init; }
}
/// <summary>
/// Result of policy compilation.
/// </summary>
internal sealed class PolicyCompileResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("inputPath")]
public string InputPath { get; init; } = string.Empty;
[JsonPropertyName("irPath")]
public string? IrPath { get; init; }
[JsonPropertyName("digest")]
public string? Digest { get; init; }
[JsonPropertyName("syntaxVersion")]
public string? SyntaxVersion { get; init; }
[JsonPropertyName("policyName")]
public string? PolicyName { get; init; }
[JsonPropertyName("ruleCount")]
public int RuleCount { get; init; }
[JsonPropertyName("profileCount")]
public int ProfileCount { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<PolicyDiagnostic>? Errors { get; init; }
[JsonPropertyName("warnings")]
public IReadOnlyList<PolicyDiagnostic>? Warnings { get; init; }
}
/// <summary>
/// Policy diagnostic message (error/warning).
/// </summary>
internal sealed class PolicyDiagnostic
{
[JsonPropertyName("code")]
public string Code { get; init; } = string.Empty;
[JsonPropertyName("message")]
public string Message { get; init; } = string.Empty;
[JsonPropertyName("severity")]
public string Severity { get; init; } = "error";
[JsonPropertyName("path")]
public string? Path { get; init; }
}
// CLI-POLICY-27-002: Policy submission/review workflow models
/// <summary>
/// Policy version bump type.
/// </summary>
internal enum PolicyBumpType
{
Patch,
Minor,
Major
}
/// <summary>
/// Policy review state.
/// </summary>
internal enum PolicyReviewState
{
Draft,
Submitted,
InReview,
Approved,
Rejected,
Published
}
/// <summary>
/// Request to bump policy version.
/// </summary>
internal sealed class PolicyVersionBumpRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("filePath")]
public string? FilePath { get; init; }
[JsonPropertyName("bumpType")]
public PolicyBumpType BumpType { get; init; } = PolicyBumpType.Patch;
[JsonPropertyName("changelog")]
public string? Changelog { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of policy version bump.
/// </summary>
internal sealed class PolicyVersionBumpResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("previousVersion")]
public int PreviousVersion { get; init; }
[JsonPropertyName("newVersion")]
public int NewVersion { get; init; }
[JsonPropertyName("changelog")]
public string? Changelog { get; init; }
[JsonPropertyName("digest")]
public string? Digest { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string>? Errors { get; init; }
}
/// <summary>
/// Request to submit policy for review.
/// </summary>
internal sealed class PolicySubmitRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int? Version { get; init; }
[JsonPropertyName("reviewers")]
public IReadOnlyList<string>? Reviewers { get; init; }
[JsonPropertyName("message")]
public string? Message { get; init; }
[JsonPropertyName("urgent")]
public bool Urgent { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of policy submission.
/// </summary>
internal sealed class PolicySubmitResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("reviewId")]
public string ReviewId { get; init; } = string.Empty;
[JsonPropertyName("state")]
public string State { get; init; } = string.Empty;
[JsonPropertyName("reviewers")]
public IReadOnlyList<string>? Reviewers { get; init; }
[JsonPropertyName("submittedAt")]
public DateTimeOffset SubmittedAt { get; init; }
[JsonPropertyName("submittedBy")]
public string? SubmittedBy { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string>? Errors { get; init; }
}
/// <summary>
/// Request to add a review comment.
/// </summary>
internal sealed class PolicyReviewCommentRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("reviewId")]
public string ReviewId { get; init; } = string.Empty;
[JsonPropertyName("comment")]
public string Comment { get; init; } = string.Empty;
[JsonPropertyName("line")]
public int? Line { get; init; }
[JsonPropertyName("ruleName")]
public string? RuleName { get; init; }
[JsonPropertyName("blocking")]
public bool Blocking { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of adding a review comment.
/// </summary>
internal sealed class PolicyReviewCommentResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("commentId")]
public string CommentId { get; init; } = string.Empty;
[JsonPropertyName("reviewId")]
public string ReviewId { get; init; } = string.Empty;
[JsonPropertyName("createdAt")]
public DateTimeOffset CreatedAt { get; init; }
[JsonPropertyName("author")]
public string? Author { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string>? Errors { get; init; }
}
/// <summary>
/// Request to approve a policy review.
/// </summary>
internal sealed class PolicyApproveRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("reviewId")]
public string ReviewId { get; init; } = string.Empty;
[JsonPropertyName("comment")]
public string? Comment { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of policy approval.
/// </summary>
internal sealed class PolicyApproveResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("reviewId")]
public string ReviewId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("state")]
public string State { get; init; } = string.Empty;
[JsonPropertyName("approvedAt")]
public DateTimeOffset ApprovedAt { get; init; }
[JsonPropertyName("approvedBy")]
public string? ApprovedBy { get; init; }
[JsonPropertyName("requiredApprovals")]
public int RequiredApprovals { get; init; }
[JsonPropertyName("currentApprovals")]
public int CurrentApprovals { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string>? Errors { get; init; }
}
/// <summary>
/// Request to reject a policy review.
/// </summary>
internal sealed class PolicyRejectRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("reviewId")]
public string ReviewId { get; init; } = string.Empty;
[JsonPropertyName("reason")]
public string Reason { get; init; } = string.Empty;
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of policy rejection.
/// </summary>
internal sealed class PolicyRejectResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("reviewId")]
public string ReviewId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("state")]
public string State { get; init; } = string.Empty;
[JsonPropertyName("rejectedAt")]
public DateTimeOffset RejectedAt { get; init; }
[JsonPropertyName("rejectedBy")]
public string? RejectedBy { get; init; }
[JsonPropertyName("reason")]
public string? Reason { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string>? Errors { get; init; }
}
/// <summary>
/// Policy review summary.
/// </summary>
internal sealed class PolicyReviewSummary
{
[JsonPropertyName("reviewId")]
public string ReviewId { get; init; } = string.Empty;
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("state")]
public string State { get; init; } = string.Empty;
[JsonPropertyName("submittedAt")]
public DateTimeOffset SubmittedAt { get; init; }
[JsonPropertyName("submittedBy")]
public string? SubmittedBy { get; init; }
[JsonPropertyName("reviewers")]
public IReadOnlyList<string>? Reviewers { get; init; }
[JsonPropertyName("approvals")]
public IReadOnlyList<PolicyApprovalInfo>? Approvals { get; init; }
[JsonPropertyName("comments")]
public IReadOnlyList<PolicyCommentInfo>? Comments { get; init; }
[JsonPropertyName("blockingComments")]
public int BlockingComments { get; init; }
[JsonPropertyName("resolvedComments")]
public int ResolvedComments { get; init; }
}
/// <summary>
/// Policy approval info.
/// </summary>
internal sealed class PolicyApprovalInfo
{
[JsonPropertyName("approver")]
public string Approver { get; init; } = string.Empty;
[JsonPropertyName("approvedAt")]
public DateTimeOffset ApprovedAt { get; init; }
[JsonPropertyName("comment")]
public string? Comment { get; init; }
}
/// <summary>
/// Policy comment info.
/// </summary>
internal sealed class PolicyCommentInfo
{
[JsonPropertyName("commentId")]
public string CommentId { get; init; } = string.Empty;
[JsonPropertyName("author")]
public string Author { get; init; } = string.Empty;
[JsonPropertyName("createdAt")]
public DateTimeOffset CreatedAt { get; init; }
[JsonPropertyName("comment")]
public string Comment { get; init; } = string.Empty;
[JsonPropertyName("line")]
public int? Line { get; init; }
[JsonPropertyName("ruleName")]
public string? RuleName { get; init; }
[JsonPropertyName("blocking")]
public bool Blocking { get; init; }
[JsonPropertyName("resolved")]
public bool Resolved { get; init; }
}
/// <summary>
/// Request to get policy review status.
/// </summary>
internal sealed class PolicyReviewStatusRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("reviewId")]
public string? ReviewId { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
// CLI-POLICY-27-004: Policy lifecycle commands (publish/promote/rollback/sign)
/// <summary>
/// Request to publish a policy revision.
/// </summary>
internal sealed class PolicyPublishRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("sign")]
public bool Sign { get; init; }
[JsonPropertyName("signatureAlgorithm")]
public string? SignatureAlgorithm { get; init; }
[JsonPropertyName("keyId")]
public string? KeyId { get; init; }
[JsonPropertyName("note")]
public string? Note { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of publishing a policy revision.
/// </summary>
internal sealed class PolicyPublishResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("publishedAt")]
public DateTimeOffset PublishedAt { get; init; }
[JsonPropertyName("signatureId")]
public string? SignatureId { get; init; }
[JsonPropertyName("rekorLogIndex")]
public string? RekorLogIndex { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string> Errors { get; init; } = Array.Empty<string>();
}
/// <summary>
/// Request to promote a policy to a target environment.
/// </summary>
internal sealed class PolicyPromoteRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("targetEnvironment")]
public string TargetEnvironment { get; init; } = string.Empty;
[JsonPropertyName("canary")]
public bool Canary { get; init; }
[JsonPropertyName("canaryPercentage")]
public int? CanaryPercentage { get; init; }
[JsonPropertyName("note")]
public string? Note { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of promoting a policy.
/// </summary>
internal sealed class PolicyPromoteResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("targetEnvironment")]
public string TargetEnvironment { get; init; } = string.Empty;
[JsonPropertyName("promotedAt")]
public DateTimeOffset PromotedAt { get; init; }
[JsonPropertyName("canaryActive")]
public bool CanaryActive { get; init; }
[JsonPropertyName("canaryPercentage")]
public int? CanaryPercentage { get; init; }
[JsonPropertyName("previousVersion")]
public int? PreviousVersion { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string> Errors { get; init; } = Array.Empty<string>();
}
/// <summary>
/// Request to rollback a policy to a previous version.
/// </summary>
internal sealed class PolicyRollbackRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("targetVersion")]
public int? TargetVersion { get; init; }
[JsonPropertyName("environment")]
public string? Environment { get; init; }
[JsonPropertyName("reason")]
public string? Reason { get; init; }
[JsonPropertyName("incidentId")]
public string? IncidentId { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of rolling back a policy.
/// </summary>
internal sealed class PolicyRollbackResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("previousVersion")]
public int PreviousVersion { get; init; }
[JsonPropertyName("rolledBackToVersion")]
public int RolledBackToVersion { get; init; }
[JsonPropertyName("rolledBackAt")]
public DateTimeOffset RolledBackAt { get; init; }
[JsonPropertyName("environment")]
public string? Environment { get; init; }
[JsonPropertyName("incidentId")]
public string? IncidentId { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string> Errors { get; init; } = Array.Empty<string>();
}
/// <summary>
/// Request to sign a policy revision.
/// </summary>
internal sealed class PolicySignRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("keyId")]
public string? KeyId { get; init; }
[JsonPropertyName("signatureAlgorithm")]
public string? SignatureAlgorithm { get; init; }
[JsonPropertyName("rekorUpload")]
public bool RekorUpload { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of signing a policy revision.
/// </summary>
internal sealed class PolicySignResult
{
[JsonPropertyName("success")]
public bool Success { get; init; }
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("signatureId")]
public string SignatureId { get; init; } = string.Empty;
[JsonPropertyName("signatureAlgorithm")]
public string SignatureAlgorithm { get; init; } = string.Empty;
[JsonPropertyName("signedAt")]
public DateTimeOffset SignedAt { get; init; }
[JsonPropertyName("keyId")]
public string? KeyId { get; init; }
[JsonPropertyName("rekorLogIndex")]
public string? RekorLogIndex { get; init; }
[JsonPropertyName("rekorEntryUuid")]
public string? RekorEntryUuid { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string> Errors { get; init; } = Array.Empty<string>();
}
/// <summary>
/// Request to verify a policy signature.
/// </summary>
internal sealed class PolicyVerifySignatureRequest
{
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("signatureId")]
public string? SignatureId { get; init; }
[JsonPropertyName("checkRekor")]
public bool CheckRekor { get; init; }
[JsonPropertyName("tenant")]
public string? Tenant { get; init; }
}
/// <summary>
/// Result of verifying a policy signature.
/// </summary>
internal sealed class PolicyVerifySignatureResult
{
[JsonPropertyName("valid")]
public bool Valid { get; init; }
[JsonPropertyName("policyId")]
public string PolicyId { get; init; } = string.Empty;
[JsonPropertyName("version")]
public int Version { get; init; }
[JsonPropertyName("signatureId")]
public string SignatureId { get; init; } = string.Empty;
[JsonPropertyName("signatureAlgorithm")]
public string SignatureAlgorithm { get; init; } = string.Empty;
[JsonPropertyName("signedAt")]
public DateTimeOffset SignedAt { get; init; }
[JsonPropertyName("signedBy")]
public string? SignedBy { get; init; }
[JsonPropertyName("keyId")]
public string? KeyId { get; init; }
[JsonPropertyName("rekorVerified")]
public bool? RekorVerified { get; init; }
[JsonPropertyName("rekorLogIndex")]
public string? RekorLogIndex { get; init; }
[JsonPropertyName("errors")]
public IReadOnlyList<string> Errors { get; init; } = Array.Empty<string>();
[JsonPropertyName("warnings")]
public IReadOnlyList<string> Warnings { get; init; } = Array.Empty<string>();
}