Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace StellaOps.Policy.Unknowns;
|
||||
|
||||
/// <summary>
|
||||
/// Unknowns budget configuration for policy evaluation.
|
||||
/// </summary>
|
||||
public sealed record UnknownsBudgetConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum allowed critical severity unknowns.
|
||||
/// </summary>
|
||||
public int MaxCriticalUnknowns { get; init; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum allowed high severity unknowns.
|
||||
/// </summary>
|
||||
public int MaxHighUnknowns { get; init; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum allowed medium severity unknowns.
|
||||
/// </summary>
|
||||
public int MaxMediumUnknowns { get; init; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum allowed low severity unknowns.
|
||||
/// </summary>
|
||||
public int MaxLowUnknowns { get; init; } = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum total unknowns across all severities.
|
||||
/// </summary>
|
||||
public int? MaxTotalUnknowns { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Action to take when budget is exceeded.
|
||||
/// </summary>
|
||||
public UnknownsBudgetAction Action { get; init; } = UnknownsBudgetAction.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Environment-specific overrides.
|
||||
/// </summary>
|
||||
public Dictionary<string, UnknownsBudgetConfig>? EnvironmentOverrides { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action to take when unknowns budget is exceeded.
|
||||
/// </summary>
|
||||
public enum UnknownsBudgetAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Block deployment/approval.
|
||||
/// </summary>
|
||||
Block,
|
||||
|
||||
/// <summary>
|
||||
/// Warn but allow deployment.
|
||||
/// </summary>
|
||||
Warn,
|
||||
|
||||
/// <summary>
|
||||
/// Log only, no enforcement.
|
||||
/// </summary>
|
||||
Log
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Counts of unknowns by severity.
|
||||
/// </summary>
|
||||
public sealed record UnknownsCounts
|
||||
{
|
||||
public int Critical { get; init; }
|
||||
public int High { get; init; }
|
||||
public int Medium { get; init; }
|
||||
public int Low { get; init; }
|
||||
public int Total => Critical + High + Medium + Low;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of unknowns budget enforcement.
|
||||
/// </summary>
|
||||
public sealed record UnknownsBudgetResult
|
||||
{
|
||||
public required bool WithinBudget { get; init; }
|
||||
public required UnknownsCounts Counts { get; init; }
|
||||
public required UnknownsBudgetConfig Budget { get; init; }
|
||||
public required UnknownsBudgetAction Action { get; init; }
|
||||
public IReadOnlyList<string>? Violations { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enforces unknowns budget for policy decisions.
|
||||
/// </summary>
|
||||
public sealed class UnknownsBudgetEnforcer
|
||||
{
|
||||
private readonly ILogger<UnknownsBudgetEnforcer> _logger;
|
||||
|
||||
public UnknownsBudgetEnforcer(ILogger<UnknownsBudgetEnforcer> logger)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate unknowns counts against budget.
|
||||
/// </summary>
|
||||
public UnknownsBudgetResult Evaluate(
|
||||
UnknownsCounts counts,
|
||||
UnknownsBudgetConfig budget,
|
||||
string? environment = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(counts);
|
||||
ArgumentNullException.ThrowIfNull(budget);
|
||||
|
||||
var effectiveBudget = GetEffectiveBudget(budget, environment);
|
||||
var violations = new List<string>();
|
||||
|
||||
if (counts.Critical > effectiveBudget.MaxCriticalUnknowns)
|
||||
{
|
||||
violations.Add($"Critical unknowns ({counts.Critical}) exceeds budget ({effectiveBudget.MaxCriticalUnknowns})");
|
||||
}
|
||||
|
||||
if (counts.High > effectiveBudget.MaxHighUnknowns)
|
||||
{
|
||||
violations.Add($"High unknowns ({counts.High}) exceeds budget ({effectiveBudget.MaxHighUnknowns})");
|
||||
}
|
||||
|
||||
if (counts.Medium > effectiveBudget.MaxMediumUnknowns)
|
||||
{
|
||||
violations.Add($"Medium unknowns ({counts.Medium}) exceeds budget ({effectiveBudget.MaxMediumUnknowns})");
|
||||
}
|
||||
|
||||
if (counts.Low > effectiveBudget.MaxLowUnknowns)
|
||||
{
|
||||
violations.Add($"Low unknowns ({counts.Low}) exceeds budget ({effectiveBudget.MaxLowUnknowns})");
|
||||
}
|
||||
|
||||
if (effectiveBudget.MaxTotalUnknowns.HasValue &&
|
||||
counts.Total > effectiveBudget.MaxTotalUnknowns.Value)
|
||||
{
|
||||
violations.Add($"Total unknowns ({counts.Total}) exceeds budget ({effectiveBudget.MaxTotalUnknowns.Value})");
|
||||
}
|
||||
|
||||
var withinBudget = violations.Count == 0;
|
||||
|
||||
if (!withinBudget)
|
||||
{
|
||||
LogViolations(violations, effectiveBudget.Action, environment);
|
||||
}
|
||||
|
||||
return new UnknownsBudgetResult
|
||||
{
|
||||
WithinBudget = withinBudget,
|
||||
Counts = counts,
|
||||
Budget = effectiveBudget,
|
||||
Action = effectiveBudget.Action,
|
||||
Violations = violations
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if deployment should be blocked based on budget result.
|
||||
/// </summary>
|
||||
public bool ShouldBlock(UnknownsBudgetResult result)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(result);
|
||||
|
||||
return !result.WithinBudget && result.Action == UnknownsBudgetAction.Block;
|
||||
}
|
||||
|
||||
private static UnknownsBudgetConfig GetEffectiveBudget(
|
||||
UnknownsBudgetConfig budget,
|
||||
string? environment)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(environment) ||
|
||||
budget.EnvironmentOverrides is null ||
|
||||
!budget.EnvironmentOverrides.TryGetValue(environment, out var override_))
|
||||
{
|
||||
return budget;
|
||||
}
|
||||
|
||||
return override_;
|
||||
}
|
||||
|
||||
private void LogViolations(
|
||||
List<string> violations,
|
||||
UnknownsBudgetAction action,
|
||||
string? environment)
|
||||
{
|
||||
var envStr = string.IsNullOrWhiteSpace(environment) ? "" : $" (env: {environment})";
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case UnknownsBudgetAction.Block:
|
||||
_logger.LogError(
|
||||
"Unknowns budget exceeded{Env}. Blocking deployment. Violations: {Violations}",
|
||||
envStr,
|
||||
string.Join("; ", violations));
|
||||
break;
|
||||
|
||||
case UnknownsBudgetAction.Warn:
|
||||
_logger.LogWarning(
|
||||
"Unknowns budget exceeded{Env}. Allowing deployment with warning. Violations: {Violations}",
|
||||
envStr,
|
||||
string.Join("; ", violations));
|
||||
break;
|
||||
|
||||
case UnknownsBudgetAction.Log:
|
||||
_logger.LogInformation(
|
||||
"Unknowns budget exceeded{Env}. Logging only. Violations: {Violations}",
|
||||
envStr,
|
||||
string.Join("; ", violations));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user