Add property-based tests for SBOM/VEX document ordering and Unicode normalization determinism
- Implement `SbomVexOrderingDeterminismProperties` for testing component list and vulnerability metadata hash consistency. - Create `UnicodeNormalizationDeterminismProperties` to validate NFC normalization and Unicode string handling. - Add project file for `StellaOps.Testing.Determinism.Properties` with necessary dependencies. - Introduce CI/CD template validation tests including YAML syntax checks and documentation content verification. - Create validation script for CI/CD templates ensuring all required files and structures are present.
This commit is contained in:
243
src/Policy/StellaOps.Policy.Gateway/Contracts/GateContracts.cs
Normal file
243
src/Policy/StellaOps.Policy.Gateway/Contracts/GateContracts.cs
Normal file
@@ -0,0 +1,243 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// Sprint: SPRINT_20251226_001_BE_cicd_gate_integration
|
||||
// Task: CICD-GATE-01 - Create gate/evaluate endpoint contracts
|
||||
|
||||
namespace StellaOps.Policy.Gateway.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to evaluate a CI/CD gate for an image.
|
||||
/// </summary>
|
||||
public sealed record GateEvaluateRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The image digest to evaluate (e.g., sha256:abc123...).
|
||||
/// </summary>
|
||||
public required string ImageDigest { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The container repository name.
|
||||
/// </summary>
|
||||
public string? Repository { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The image tag, if any.
|
||||
/// </summary>
|
||||
public string? Tag { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The baseline reference for comparison.
|
||||
/// Can be a snapshot ID, image digest, or strategy name (e.g., "last-approved", "production").
|
||||
/// </summary>
|
||||
public string? BaselineRef { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional policy ID to use for evaluation.
|
||||
/// </summary>
|
||||
public string? PolicyId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to allow override of blocking gates.
|
||||
/// </summary>
|
||||
public bool AllowOverride { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Justification for override (required if AllowOverride is true and gate would block).
|
||||
/// </summary>
|
||||
public string? OverrideJustification { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Source of the request (e.g., "cli", "api", "webhook").
|
||||
/// </summary>
|
||||
public string? Source { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// CI/CD context identifier (e.g., "github-actions", "gitlab-ci").
|
||||
/// </summary>
|
||||
public string? CiContext { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional context for the gate evaluation.
|
||||
/// </summary>
|
||||
public GateEvaluationContext? Context { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Additional context for gate evaluation.
|
||||
/// </summary>
|
||||
public sealed record GateEvaluationContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Git branch name.
|
||||
/// </summary>
|
||||
public string? Branch { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Git commit SHA.
|
||||
/// </summary>
|
||||
public string? CommitSha { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// CI/CD pipeline ID or job ID.
|
||||
/// </summary>
|
||||
public string? PipelineId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Environment being deployed to (e.g., "production", "staging").
|
||||
/// </summary>
|
||||
public string? Environment { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Actor triggering the gate (e.g., user or service identity).
|
||||
/// </summary>
|
||||
public string? Actor { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from gate evaluation.
|
||||
/// </summary>
|
||||
public sealed record GateEvaluateResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique decision ID for audit and tracking.
|
||||
/// </summary>
|
||||
public required string DecisionId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The gate decision status.
|
||||
/// </summary>
|
||||
public required GateStatus Status { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Suggested CI exit code.
|
||||
/// 0 = Pass, 1 = Warn (configurable pass-through), 2 = Fail/Block
|
||||
/// </summary>
|
||||
public required int ExitCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The image digest that was evaluated.
|
||||
/// </summary>
|
||||
public required string ImageDigest { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The baseline reference used for comparison.
|
||||
/// </summary>
|
||||
public string? BaselineRef { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the decision was made (UTC).
|
||||
/// </summary>
|
||||
public required DateTimeOffset DecidedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Summary message for the decision.
|
||||
/// </summary>
|
||||
public string? Summary { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Advisory or suggestion for the developer.
|
||||
/// </summary>
|
||||
public string? Advisory { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// List of gate results.
|
||||
/// </summary>
|
||||
public IReadOnlyList<GateResultDto>? Gates { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gate that caused the block (if blocked).
|
||||
/// </summary>
|
||||
public string? BlockedBy { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Detailed reason for the block.
|
||||
/// </summary>
|
||||
public string? BlockReason { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Suggestion for resolving the block.
|
||||
/// </summary>
|
||||
public string? Suggestion { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether an override was applied.
|
||||
/// </summary>
|
||||
public bool OverrideApplied { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Delta summary if available.
|
||||
/// </summary>
|
||||
public DeltaSummaryDto? DeltaSummary { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of a single gate evaluation.
|
||||
/// </summary>
|
||||
public sealed record GateResultDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gate name/ID.
|
||||
/// </summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gate result type.
|
||||
/// </summary>
|
||||
public required string Result { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Reason for the result.
|
||||
/// </summary>
|
||||
public required string Reason { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional note.
|
||||
/// </summary>
|
||||
public string? Note { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Condition expression that was evaluated.
|
||||
/// </summary>
|
||||
public string? Condition { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gate evaluation status.
|
||||
/// </summary>
|
||||
public enum GateStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Gate passed - proceed with deployment.
|
||||
/// </summary>
|
||||
Pass = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Gate produced warnings - proceed with caution.
|
||||
/// </summary>
|
||||
Warn = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Gate blocked - do not proceed.
|
||||
/// </summary>
|
||||
Fail = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CI exit codes for gate evaluation.
|
||||
/// </summary>
|
||||
public static class GateExitCodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Gate passed - proceed with deployment.
|
||||
/// </summary>
|
||||
public const int Pass = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gate produced warnings - configurable pass-through.
|
||||
/// </summary>
|
||||
public const int Warn = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Gate blocked - do not proceed.
|
||||
/// </summary>
|
||||
public const int Fail = 2;
|
||||
}
|
||||
Reference in New Issue
Block a user