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
- 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.
1203 lines
31 KiB
C#
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>();
|
|
}
|