Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Scanner.Reachability.Slices;
|
||||
|
||||
/// <summary>
|
||||
/// Policy binding mode for slices.
|
||||
/// </summary>
|
||||
public enum PolicyBindingMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Slice is invalid if policy changes at all.
|
||||
/// </summary>
|
||||
Strict,
|
||||
|
||||
/// <summary>
|
||||
/// Slice is valid with newer policy versions only.
|
||||
/// </summary>
|
||||
Forward,
|
||||
|
||||
/// <summary>
|
||||
/// Slice is valid with any policy version.
|
||||
/// </summary>
|
||||
Any
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Policy binding information for a reachability slice.
|
||||
/// </summary>
|
||||
public sealed record PolicyBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Content-addressed hash of the policy DSL.
|
||||
/// </summary>
|
||||
[JsonPropertyName("policyDigest")]
|
||||
public required string PolicyDigest { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Semantic version of the policy.
|
||||
/// </summary>
|
||||
[JsonPropertyName("policyVersion")]
|
||||
public required string PolicyVersion { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the policy was bound to this slice.
|
||||
/// </summary>
|
||||
[JsonPropertyName("boundAt")]
|
||||
public required DateTimeOffset BoundAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Binding mode for validation.
|
||||
/// </summary>
|
||||
[JsonPropertyName("mode")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public required PolicyBindingMode Mode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional policy name/identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("policyName")]
|
||||
public string? PolicyName { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional policy source (e.g., git commit hash).
|
||||
/// </summary>
|
||||
[JsonPropertyName("policySource")]
|
||||
public string? PolicySource { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of policy binding validation.
|
||||
/// </summary>
|
||||
public sealed record PolicyBindingValidationResult
|
||||
{
|
||||
public required bool Valid { get; init; }
|
||||
public string? FailureReason { get; init; }
|
||||
public required PolicyBinding SlicePolicy { get; init; }
|
||||
public required PolicyBinding CurrentPolicy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validator for policy bindings.
|
||||
/// </summary>
|
||||
public sealed class PolicyBindingValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Validate a policy binding against current policy.
|
||||
/// </summary>
|
||||
public PolicyBindingValidationResult Validate(
|
||||
PolicyBinding sliceBinding,
|
||||
PolicyBinding currentPolicy)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(sliceBinding);
|
||||
ArgumentNullException.ThrowIfNull(currentPolicy);
|
||||
|
||||
var result = sliceBinding.Mode switch
|
||||
{
|
||||
PolicyBindingMode.Strict => ValidateStrict(sliceBinding, currentPolicy),
|
||||
PolicyBindingMode.Forward => ValidateForward(sliceBinding, currentPolicy),
|
||||
PolicyBindingMode.Any => ValidateAny(sliceBinding, currentPolicy),
|
||||
_ => throw new ArgumentException($"Unknown policy binding mode: {sliceBinding.Mode}")
|
||||
};
|
||||
|
||||
return result with
|
||||
{
|
||||
SlicePolicy = sliceBinding,
|
||||
CurrentPolicy = currentPolicy
|
||||
};
|
||||
}
|
||||
|
||||
private static PolicyBindingValidationResult ValidateStrict(
|
||||
PolicyBinding sliceBinding,
|
||||
PolicyBinding currentPolicy)
|
||||
{
|
||||
var digestMatch = string.Equals(
|
||||
sliceBinding.PolicyDigest,
|
||||
currentPolicy.PolicyDigest,
|
||||
StringComparison.Ordinal);
|
||||
|
||||
return new PolicyBindingValidationResult
|
||||
{
|
||||
Valid = digestMatch,
|
||||
FailureReason = digestMatch
|
||||
? null
|
||||
: $"Policy digest mismatch. Slice bound to {sliceBinding.PolicyDigest}, current is {currentPolicy.PolicyDigest}.",
|
||||
SlicePolicy = sliceBinding,
|
||||
CurrentPolicy = currentPolicy
|
||||
};
|
||||
}
|
||||
|
||||
private static PolicyBindingValidationResult ValidateForward(
|
||||
PolicyBinding sliceBinding,
|
||||
PolicyBinding currentPolicy)
|
||||
{
|
||||
// Check if current policy version is newer or equal
|
||||
if (!Version.TryParse(sliceBinding.PolicyVersion, out var sliceVersion) ||
|
||||
!Version.TryParse(currentPolicy.PolicyVersion, out var currentVersion))
|
||||
{
|
||||
return new PolicyBindingValidationResult
|
||||
{
|
||||
Valid = false,
|
||||
FailureReason = "Invalid version format for forward compatibility check.",
|
||||
SlicePolicy = sliceBinding,
|
||||
CurrentPolicy = currentPolicy
|
||||
};
|
||||
}
|
||||
|
||||
var isForwardCompatible = currentVersion >= sliceVersion;
|
||||
|
||||
return new PolicyBindingValidationResult
|
||||
{
|
||||
Valid = isForwardCompatible,
|
||||
FailureReason = isForwardCompatible
|
||||
? null
|
||||
: $"Policy version downgrade detected. Slice bound to {sliceVersion}, current is {currentVersion}.",
|
||||
SlicePolicy = sliceBinding,
|
||||
CurrentPolicy = currentPolicy
|
||||
};
|
||||
}
|
||||
|
||||
private static PolicyBindingValidationResult ValidateAny(
|
||||
PolicyBinding sliceBinding,
|
||||
PolicyBinding currentPolicy)
|
||||
{
|
||||
// Always valid in 'any' mode
|
||||
return new PolicyBindingValidationResult
|
||||
{
|
||||
Valid = true,
|
||||
FailureReason = null,
|
||||
SlicePolicy = sliceBinding,
|
||||
CurrentPolicy = currentPolicy
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user