89 lines
2.6 KiB
C#
89 lines
2.6 KiB
C#
|
|
using StellaOps.Policy.TrustLattice;
|
|
using System.Collections.Immutable;
|
|
using VexStatus = StellaOps.Policy.Confidence.Models.VexStatus;
|
|
|
|
namespace StellaOps.Policy.Gates;
|
|
|
|
public sealed record MinimumConfidenceGateOptions
|
|
{
|
|
public bool Enabled { get; init; } = true;
|
|
public IReadOnlyDictionary<string, double> Thresholds { get; init; } = new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
["production"] = 0.75,
|
|
["staging"] = 0.60,
|
|
["development"] = 0.40,
|
|
};
|
|
public IReadOnlyCollection<VexStatus> ApplyToStatuses { get; init; } = new[]
|
|
{
|
|
VexStatus.NotAffected,
|
|
VexStatus.Fixed,
|
|
};
|
|
}
|
|
|
|
public sealed class MinimumConfidenceGate : IPolicyGate
|
|
{
|
|
private readonly MinimumConfidenceGateOptions _options;
|
|
|
|
public MinimumConfidenceGate(MinimumConfidenceGateOptions? options = null)
|
|
{
|
|
_options = options ?? new MinimumConfidenceGateOptions();
|
|
}
|
|
|
|
public Task<GateResult> EvaluateAsync(MergeResult mergeResult, PolicyGateContext context, CancellationToken ct = default)
|
|
{
|
|
if (!_options.Enabled)
|
|
{
|
|
return Task.FromResult(Pass("disabled"));
|
|
}
|
|
|
|
if (mergeResult.Status == VexStatus.Affected)
|
|
{
|
|
return Task.FromResult(Pass("affected_bypass"));
|
|
}
|
|
|
|
if (!_options.ApplyToStatuses.Contains(mergeResult.Status))
|
|
{
|
|
return Task.FromResult(Pass("status_not_applicable"));
|
|
}
|
|
|
|
var threshold = GetThreshold(context.Environment);
|
|
var passed = mergeResult.Confidence >= threshold;
|
|
var details = ImmutableDictionary<string, object>.Empty
|
|
.Add("threshold", threshold)
|
|
.Add("confidence", mergeResult.Confidence)
|
|
.Add("environment", context.Environment);
|
|
|
|
return Task.FromResult(new GateResult
|
|
{
|
|
GateName = nameof(MinimumConfidenceGate),
|
|
Passed = passed,
|
|
Reason = passed ? null : "confidence_below_threshold",
|
|
Details = details,
|
|
});
|
|
}
|
|
|
|
private double GetThreshold(string environment)
|
|
{
|
|
if (_options.Thresholds.TryGetValue(environment, out var threshold))
|
|
{
|
|
return threshold;
|
|
}
|
|
|
|
if (_options.Thresholds.TryGetValue("production", out var prod))
|
|
{
|
|
return prod;
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
private static GateResult Pass(string reason) => new()
|
|
{
|
|
GateName = nameof(MinimumConfidenceGate),
|
|
Passed = true,
|
|
Reason = reason,
|
|
Details = ImmutableDictionary<string, object>.Empty,
|
|
};
|
|
}
|