up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-13 00:20:26 +02:00
parent e1f1bef4c1
commit 564df71bfb
2376 changed files with 334389 additions and 328032 deletions

View File

@@ -1,161 +1,161 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Excititor.Core;
namespace StellaOps.Excititor.Policy;
public interface IVexPolicyProvider
{
VexPolicySnapshot GetSnapshot();
}
public interface IVexPolicyEvaluator
{
string Version { get; }
VexPolicySnapshot Snapshot { get; }
double GetProviderWeight(VexProvider provider);
bool IsClaimEligible(VexClaim claim, VexProvider provider, out string? rejectionReason);
}
public sealed record VexPolicySnapshot(
string Version,
VexConsensusPolicyOptions ConsensusOptions,
IVexConsensusPolicy ConsensusPolicy,
ImmutableArray<VexPolicyIssue> Issues,
string RevisionId,
string Digest)
{
public static readonly VexPolicySnapshot Default = new(
VexConsensusPolicyOptions.BaselineVersion,
new VexConsensusPolicyOptions(),
new BaselineVexConsensusPolicy(),
ImmutableArray<VexPolicyIssue>.Empty,
"rev-0",
string.Empty);
}
public sealed record VexPolicyIssue(
string Code,
string Message,
VexPolicyIssueSeverity Severity);
public enum VexPolicyIssueSeverity
{
Warning,
Error,
}
public sealed class VexPolicyProvider : IVexPolicyProvider
{
private readonly IOptionsMonitor<VexPolicyOptions> _options;
private readonly ILogger<VexPolicyProvider> _logger;
private readonly object _sync = new();
private long _revisionCounter;
private string? _currentRevisionId;
private string? _currentDigest;
public VexPolicyProvider(
IOptionsMonitor<VexPolicyOptions> options,
ILogger<VexPolicyProvider> logger)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public VexPolicySnapshot GetSnapshot()
{
var options = _options.CurrentValue ?? new VexPolicyOptions();
return BuildSnapshot(options);
}
private VexPolicySnapshot BuildSnapshot(VexPolicyOptions options)
{
var normalization = VexPolicyProcessing.Normalize(options);
var digest = VexPolicyDigest.Compute(normalization.ConsensusOptions);
string revisionId;
bool isNewRevision;
lock (_sync)
{
if (!string.Equals(_currentDigest, digest, StringComparison.Ordinal))
{
_revisionCounter++;
revisionId = $"rev-{_revisionCounter}";
_currentDigest = digest;
_currentRevisionId = revisionId;
isNewRevision = true;
}
else
{
revisionId = _currentRevisionId ?? "rev-0";
isNewRevision = false;
}
}
var policy = new BaselineVexConsensusPolicy(normalization.ConsensusOptions);
var snapshot = new VexPolicySnapshot(
normalization.ConsensusOptions.Version,
normalization.ConsensusOptions,
policy,
normalization.Issues,
revisionId,
digest);
if (isNewRevision)
{
_logger.LogInformation(
"Policy snapshot updated: revision {RevisionId}, version {Version}, digest {Digest}, issues {IssueCount}",
snapshot.RevisionId,
snapshot.Version,
snapshot.Digest,
snapshot.Issues.Length);
VexPolicyTelemetry.RecordReload(snapshot.RevisionId, snapshot.Version, snapshot.Issues.Length);
}
else if (snapshot.Issues.Length > 0)
{
foreach (var issue in snapshot.Issues)
{
_logger.LogWarning("Policy issue {Code}: {Message}", issue.Code, issue.Message);
}
}
return snapshot;
}
}
public sealed class VexPolicyEvaluator : IVexPolicyEvaluator
{
private readonly IVexPolicyProvider _provider;
public VexPolicyEvaluator(IVexPolicyProvider provider)
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
}
public string Version => Snapshot.Version;
public VexPolicySnapshot Snapshot => _provider.GetSnapshot();
public double GetProviderWeight(VexProvider provider)
=> Snapshot.ConsensusPolicy.GetProviderWeight(provider);
public bool IsClaimEligible(VexClaim claim, VexProvider provider, out string? rejectionReason)
=> Snapshot.ConsensusPolicy.IsClaimEligible(claim, provider, out rejectionReason);
}
public static class VexPolicyServiceCollectionExtensions
{
public static IServiceCollection AddVexPolicy(this IServiceCollection services)
{
services.AddSingleton<IVexPolicyProvider, VexPolicyProvider>();
services.AddSingleton<IVexPolicyEvaluator, VexPolicyEvaluator>();
return services;
}
}
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Excititor.Core;
namespace StellaOps.Excititor.Policy;
public interface IVexPolicyProvider
{
VexPolicySnapshot GetSnapshot();
}
public interface IVexPolicyEvaluator
{
string Version { get; }
VexPolicySnapshot Snapshot { get; }
double GetProviderWeight(VexProvider provider);
bool IsClaimEligible(VexClaim claim, VexProvider provider, out string? rejectionReason);
}
public sealed record VexPolicySnapshot(
string Version,
VexConsensusPolicyOptions ConsensusOptions,
IVexConsensusPolicy ConsensusPolicy,
ImmutableArray<VexPolicyIssue> Issues,
string RevisionId,
string Digest)
{
public static readonly VexPolicySnapshot Default = new(
VexConsensusPolicyOptions.BaselineVersion,
new VexConsensusPolicyOptions(),
new BaselineVexConsensusPolicy(),
ImmutableArray<VexPolicyIssue>.Empty,
"rev-0",
string.Empty);
}
public sealed record VexPolicyIssue(
string Code,
string Message,
VexPolicyIssueSeverity Severity);
public enum VexPolicyIssueSeverity
{
Warning,
Error,
}
public sealed class VexPolicyProvider : IVexPolicyProvider
{
private readonly IOptionsMonitor<VexPolicyOptions> _options;
private readonly ILogger<VexPolicyProvider> _logger;
private readonly object _sync = new();
private long _revisionCounter;
private string? _currentRevisionId;
private string? _currentDigest;
public VexPolicyProvider(
IOptionsMonitor<VexPolicyOptions> options,
ILogger<VexPolicyProvider> logger)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public VexPolicySnapshot GetSnapshot()
{
var options = _options.CurrentValue ?? new VexPolicyOptions();
return BuildSnapshot(options);
}
private VexPolicySnapshot BuildSnapshot(VexPolicyOptions options)
{
var normalization = VexPolicyProcessing.Normalize(options);
var digest = VexPolicyDigest.Compute(normalization.ConsensusOptions);
string revisionId;
bool isNewRevision;
lock (_sync)
{
if (!string.Equals(_currentDigest, digest, StringComparison.Ordinal))
{
_revisionCounter++;
revisionId = $"rev-{_revisionCounter}";
_currentDigest = digest;
_currentRevisionId = revisionId;
isNewRevision = true;
}
else
{
revisionId = _currentRevisionId ?? "rev-0";
isNewRevision = false;
}
}
var policy = new BaselineVexConsensusPolicy(normalization.ConsensusOptions);
var snapshot = new VexPolicySnapshot(
normalization.ConsensusOptions.Version,
normalization.ConsensusOptions,
policy,
normalization.Issues,
revisionId,
digest);
if (isNewRevision)
{
_logger.LogInformation(
"Policy snapshot updated: revision {RevisionId}, version {Version}, digest {Digest}, issues {IssueCount}",
snapshot.RevisionId,
snapshot.Version,
snapshot.Digest,
snapshot.Issues.Length);
VexPolicyTelemetry.RecordReload(snapshot.RevisionId, snapshot.Version, snapshot.Issues.Length);
}
else if (snapshot.Issues.Length > 0)
{
foreach (var issue in snapshot.Issues)
{
_logger.LogWarning("Policy issue {Code}: {Message}", issue.Code, issue.Message);
}
}
return snapshot;
}
}
public sealed class VexPolicyEvaluator : IVexPolicyEvaluator
{
private readonly IVexPolicyProvider _provider;
public VexPolicyEvaluator(IVexPolicyProvider provider)
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
}
public string Version => Snapshot.Version;
public VexPolicySnapshot Snapshot => _provider.GetSnapshot();
public double GetProviderWeight(VexProvider provider)
=> Snapshot.ConsensusPolicy.GetProviderWeight(provider);
public bool IsClaimEligible(VexClaim claim, VexProvider provider, out string? rejectionReason)
=> Snapshot.ConsensusPolicy.IsClaimEligible(claim, provider, out rejectionReason);
}
public static class VexPolicyServiceCollectionExtensions
{
public static IServiceCollection AddVexPolicy(this IServiceCollection services)
{
services.AddSingleton<IVexPolicyProvider, VexPolicyProvider>();
services.AddSingleton<IVexPolicyEvaluator, VexPolicyEvaluator>();
return services;
}
}

View File

@@ -1,94 +1,94 @@
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using StellaOps.Excititor.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace StellaOps.Excititor.Policy;
public enum VexPolicyDocumentFormat
{
Json,
Yaml,
}
public sealed record VexPolicyBindingResult(
bool Success,
VexPolicyOptions? Options,
VexConsensusPolicyOptions? NormalizedOptions,
ImmutableArray<VexPolicyIssue> Issues);
public static class VexPolicyBinder
{
public static VexPolicyBindingResult Bind(string content, VexPolicyDocumentFormat format)
{
if (string.IsNullOrWhiteSpace(content))
{
return Failure("policy.empty", "Policy document is empty.");
}
try
{
var options = Parse(content, format);
return Normalize(options);
}
catch (JsonException ex)
{
return Failure("policy.parse.json", $"Failed to parse JSON policy document: {ex.Message}");
}
catch (YamlDotNet.Core.YamlException ex)
{
return Failure("policy.parse.yaml", $"Failed to parse YAML policy document: {ex.Message}");
}
}
public static VexPolicyBindingResult Bind(Stream stream, VexPolicyDocumentFormat format, Encoding? encoding = null)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
encoding ??= Encoding.UTF8;
using var reader = new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks: true, leaveOpen: true);
var content = reader.ReadToEnd();
return Bind(content, format);
}
private static VexPolicyBindingResult Normalize(VexPolicyOptions options)
{
var normalization = VexPolicyProcessing.Normalize(options);
var hasErrors = normalization.Issues.Any(static issue => issue.Severity == VexPolicyIssueSeverity.Error);
return new VexPolicyBindingResult(!hasErrors, options, normalization.ConsensusOptions, normalization.Issues);
}
private static VexPolicyBindingResult Failure(string code, string message)
{
var issue = new VexPolicyIssue(code, message, VexPolicyIssueSeverity.Error);
return new VexPolicyBindingResult(false, null, null, ImmutableArray.Create(issue));
}
private static VexPolicyOptions Parse(string content, VexPolicyDocumentFormat format)
{
return format switch
{
VexPolicyDocumentFormat.Json => JsonSerializer.Deserialize<VexPolicyOptions>(content, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true,
}) ?? new VexPolicyOptions(),
VexPolicyDocumentFormat.Yaml => BuildYamlDeserializer().Deserialize<VexPolicyOptions>(content) ?? new VexPolicyOptions(),
_ => throw new ArgumentOutOfRangeException(nameof(format), format, "Unsupported policy document format."),
};
}
private static IDeserializer BuildYamlDeserializer()
=> new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build();
}
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using StellaOps.Excititor.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace StellaOps.Excititor.Policy;
public enum VexPolicyDocumentFormat
{
Json,
Yaml,
}
public sealed record VexPolicyBindingResult(
bool Success,
VexPolicyOptions? Options,
VexConsensusPolicyOptions? NormalizedOptions,
ImmutableArray<VexPolicyIssue> Issues);
public static class VexPolicyBinder
{
public static VexPolicyBindingResult Bind(string content, VexPolicyDocumentFormat format)
{
if (string.IsNullOrWhiteSpace(content))
{
return Failure("policy.empty", "Policy document is empty.");
}
try
{
var options = Parse(content, format);
return Normalize(options);
}
catch (JsonException ex)
{
return Failure("policy.parse.json", $"Failed to parse JSON policy document: {ex.Message}");
}
catch (YamlDotNet.Core.YamlException ex)
{
return Failure("policy.parse.yaml", $"Failed to parse YAML policy document: {ex.Message}");
}
}
public static VexPolicyBindingResult Bind(Stream stream, VexPolicyDocumentFormat format, Encoding? encoding = null)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
encoding ??= Encoding.UTF8;
using var reader = new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks: true, leaveOpen: true);
var content = reader.ReadToEnd();
return Bind(content, format);
}
private static VexPolicyBindingResult Normalize(VexPolicyOptions options)
{
var normalization = VexPolicyProcessing.Normalize(options);
var hasErrors = normalization.Issues.Any(static issue => issue.Severity == VexPolicyIssueSeverity.Error);
return new VexPolicyBindingResult(!hasErrors, options, normalization.ConsensusOptions, normalization.Issues);
}
private static VexPolicyBindingResult Failure(string code, string message)
{
var issue = new VexPolicyIssue(code, message, VexPolicyIssueSeverity.Error);
return new VexPolicyBindingResult(false, null, null, ImmutableArray.Create(issue));
}
private static VexPolicyOptions Parse(string content, VexPolicyDocumentFormat format)
{
return format switch
{
VexPolicyDocumentFormat.Json => JsonSerializer.Deserialize<VexPolicyOptions>(content, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true,
}) ?? new VexPolicyOptions(),
VexPolicyDocumentFormat.Yaml => BuildYamlDeserializer().Deserialize<VexPolicyOptions>(content) ?? new VexPolicyOptions(),
_ => throw new ArgumentOutOfRangeException(nameof(format), format, "Unsupported policy document format."),
};
}
private static IDeserializer BuildYamlDeserializer()
=> new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build();
}

View File

@@ -1,87 +1,87 @@
using System;
using System.Collections.Immutable;
using System.Linq;
namespace StellaOps.Excititor.Policy;
public interface IVexPolicyDiagnostics
{
VexPolicyDiagnosticsReport GetDiagnostics();
}
public sealed record VexPolicyDiagnosticsReport(
string Version,
string RevisionId,
string Digest,
int ErrorCount,
int WarningCount,
DateTimeOffset GeneratedAt,
ImmutableArray<VexPolicyIssue> Issues,
ImmutableArray<string> Recommendations,
ImmutableDictionary<string, double> ActiveOverrides);
public sealed class VexPolicyDiagnostics : IVexPolicyDiagnostics
{
private readonly IVexPolicyProvider _policyProvider;
private readonly TimeProvider _timeProvider;
public VexPolicyDiagnostics(
IVexPolicyProvider policyProvider,
TimeProvider? timeProvider = null)
{
_policyProvider = policyProvider ?? throw new ArgumentNullException(nameof(policyProvider));
_timeProvider = timeProvider ?? TimeProvider.System;
}
public VexPolicyDiagnosticsReport GetDiagnostics()
{
var snapshot = _policyProvider.GetSnapshot();
var issues = snapshot.Issues;
var errorCount = issues.Count(static issue => issue.Severity == VexPolicyIssueSeverity.Error);
var warningCount = issues.Count(static issue => issue.Severity == VexPolicyIssueSeverity.Warning);
var overrides = snapshot.ConsensusOptions.ProviderOverrides
.OrderBy(static pair => pair.Key, StringComparer.Ordinal)
.ToImmutableDictionary();
var recommendations = BuildRecommendations(errorCount, warningCount, overrides);
return new VexPolicyDiagnosticsReport(
snapshot.Version,
snapshot.RevisionId,
snapshot.Digest,
errorCount,
warningCount,
_timeProvider.GetUtcNow(),
issues,
recommendations,
overrides);
}
private static ImmutableArray<string> BuildRecommendations(
int errorCount,
int warningCount,
ImmutableDictionary<string, double> overrides)
{
var messages = ImmutableArray.CreateBuilder<string>();
if (errorCount > 0)
{
messages.Add("Resolve policy errors before running consensus; defaults are used while errors persist.");
}
if (warningCount > 0)
{
messages.Add("Review policy warnings via CLI/Web diagnostics and adjust configuration as needed.");
}
if (overrides.Count > 0)
{
messages.Add($"Provider overrides active for: {string.Join(", ", overrides.Keys)}.");
}
messages.Add("Refer to docs/modules/excititor/architecture.md for policy upgrade and diagnostics guidance.");
return messages.ToImmutable();
}
}
using System;
using System.Collections.Immutable;
using System.Linq;
namespace StellaOps.Excititor.Policy;
public interface IVexPolicyDiagnostics
{
VexPolicyDiagnosticsReport GetDiagnostics();
}
public sealed record VexPolicyDiagnosticsReport(
string Version,
string RevisionId,
string Digest,
int ErrorCount,
int WarningCount,
DateTimeOffset GeneratedAt,
ImmutableArray<VexPolicyIssue> Issues,
ImmutableArray<string> Recommendations,
ImmutableDictionary<string, double> ActiveOverrides);
public sealed class VexPolicyDiagnostics : IVexPolicyDiagnostics
{
private readonly IVexPolicyProvider _policyProvider;
private readonly TimeProvider _timeProvider;
public VexPolicyDiagnostics(
IVexPolicyProvider policyProvider,
TimeProvider? timeProvider = null)
{
_policyProvider = policyProvider ?? throw new ArgumentNullException(nameof(policyProvider));
_timeProvider = timeProvider ?? TimeProvider.System;
}
public VexPolicyDiagnosticsReport GetDiagnostics()
{
var snapshot = _policyProvider.GetSnapshot();
var issues = snapshot.Issues;
var errorCount = issues.Count(static issue => issue.Severity == VexPolicyIssueSeverity.Error);
var warningCount = issues.Count(static issue => issue.Severity == VexPolicyIssueSeverity.Warning);
var overrides = snapshot.ConsensusOptions.ProviderOverrides
.OrderBy(static pair => pair.Key, StringComparer.Ordinal)
.ToImmutableDictionary();
var recommendations = BuildRecommendations(errorCount, warningCount, overrides);
return new VexPolicyDiagnosticsReport(
snapshot.Version,
snapshot.RevisionId,
snapshot.Digest,
errorCount,
warningCount,
_timeProvider.GetUtcNow(),
issues,
recommendations,
overrides);
}
private static ImmutableArray<string> BuildRecommendations(
int errorCount,
int warningCount,
ImmutableDictionary<string, double> overrides)
{
var messages = ImmutableArray.CreateBuilder<string>();
if (errorCount > 0)
{
messages.Add("Resolve policy errors before running consensus; defaults are used while errors persist.");
}
if (warningCount > 0)
{
messages.Add("Review policy warnings via CLI/Web diagnostics and adjust configuration as needed.");
}
if (overrides.Count > 0)
{
messages.Add($"Provider overrides active for: {string.Join(", ", overrides.Keys)}.");
}
messages.Add("Refer to docs/modules/excititor/architecture.md for policy upgrade and diagnostics guidance.");
return messages.ToImmutable();
}
}

View File

@@ -1,38 +1,38 @@
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using StellaOps.Excititor.Core;
namespace StellaOps.Excititor.Policy;
internal static class VexPolicyDigest
{
public static string Compute(VexConsensusPolicyOptions options)
{
ArgumentNullException.ThrowIfNull(options);
var builder = new StringBuilder();
builder.Append(options.Version).Append('|')
.Append(options.VendorWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.DistroWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.PlatformWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.HubWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.AttestationWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.WeightCeiling.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.Alpha.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.Beta.ToString("F6", CultureInfo.InvariantCulture));
foreach (var kvp in options.ProviderOverrides
.OrderBy(static pair => pair.Key, StringComparer.Ordinal))
{
builder.Append('|')
.Append(kvp.Key)
.Append('=')
.Append(kvp.Value.ToString("F6", CultureInfo.InvariantCulture));
}
var input = builder.ToString();
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(input));
return Convert.ToHexString(hash);
}
}
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using StellaOps.Excititor.Core;
namespace StellaOps.Excititor.Policy;
internal static class VexPolicyDigest
{
public static string Compute(VexConsensusPolicyOptions options)
{
ArgumentNullException.ThrowIfNull(options);
var builder = new StringBuilder();
builder.Append(options.Version).Append('|')
.Append(options.VendorWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.DistroWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.PlatformWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.HubWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.AttestationWeight.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.WeightCeiling.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.Alpha.ToString("F6", CultureInfo.InvariantCulture)).Append('|')
.Append(options.Beta.ToString("F6", CultureInfo.InvariantCulture));
foreach (var kvp in options.ProviderOverrides
.OrderBy(static pair => pair.Key, StringComparer.Ordinal))
{
builder.Append('|')
.Append(kvp.Key)
.Append('=')
.Append(kvp.Value.ToString("F6", CultureInfo.InvariantCulture));
}
var input = builder.ToString();
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(input));
return Convert.ToHexString(hash);
}
}

View File

@@ -1,36 +1,36 @@
using System.Collections.Generic;
namespace StellaOps.Excititor.Policy;
public sealed class VexPolicyOptions
{
public string? Version { get; set; }
public VexPolicyWeightOptions Weights { get; set; } = new();
public VexPolicyScoringOptions Scoring { get; set; } = new();
public IDictionary<string, double>? ProviderOverrides { get; set; }
}
public sealed class VexPolicyWeightOptions
{
public double? Vendor { get; set; }
public double? Distro { get; set; }
public double? Platform { get; set; }
public double? Hub { get; set; }
public double? Attestation { get; set; }
public double? Ceiling { get; set; }
}
public sealed class VexPolicyScoringOptions
{
public double? Alpha { get; set; }
public double? Beta { get; set; }
}
using System.Collections.Generic;
namespace StellaOps.Excititor.Policy;
public sealed class VexPolicyOptions
{
public string? Version { get; set; }
public VexPolicyWeightOptions Weights { get; set; } = new();
public VexPolicyScoringOptions Scoring { get; set; } = new();
public IDictionary<string, double>? ProviderOverrides { get; set; }
}
public sealed class VexPolicyWeightOptions
{
public double? Vendor { get; set; }
public double? Distro { get; set; }
public double? Platform { get; set; }
public double? Hub { get; set; }
public double? Attestation { get; set; }
public double? Ceiling { get; set; }
}
public sealed class VexPolicyScoringOptions
{
public double? Alpha { get; set; }
public double? Beta { get; set; }
}

View File

@@ -1,282 +1,282 @@
using System.Collections.Immutable;
using System.Globalization;
using StellaOps.Excititor.Core;
namespace StellaOps.Excititor.Policy;
internal static class VexPolicyProcessing
{
private const double DefaultVendorWeight = 1.0;
private const double DefaultDistroWeight = 0.9;
private const double DefaultPlatformWeight = 0.7;
private const double DefaultHubWeight = 0.5;
private const double DefaultAttestationWeight = 0.6;
public static VexPolicyNormalizationResult Normalize(VexPolicyOptions? options)
{
var issues = ImmutableArray.CreateBuilder<VexPolicyIssue>();
var policyOptions = options ?? new VexPolicyOptions();
var normalizedWeights = NormalizeWeights(policyOptions.Weights, issues);
var overrides = NormalizeOverrides(policyOptions.ProviderOverrides, normalizedWeights.Ceiling, issues);
var scoring = NormalizeScoring(policyOptions.Scoring, issues);
var consensusOptions = new VexConsensusPolicyOptions(
policyOptions.Version ?? VexConsensusPolicyOptions.BaselineVersion,
normalizedWeights.Vendor,
normalizedWeights.Distro,
normalizedWeights.Platform,
normalizedWeights.Hub,
normalizedWeights.Attestation,
overrides,
normalizedWeights.Ceiling,
scoring.Alpha,
scoring.Beta);
var orderedIssues = issues.ToImmutable().Sort(IssueComparer);
return new VexPolicyNormalizationResult(consensusOptions, orderedIssues);
}
public static ImmutableArray<VexPolicyIssue> SortIssues(IEnumerable<VexPolicyIssue> issues)
=> issues.ToImmutableArray().Sort(IssueComparer);
private static WeightNormalizationResult NormalizeWeights(
VexPolicyWeightOptions? options,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
var ceiling = NormalizeWeightCeiling(options?.Ceiling, issues);
var vendor = NormalizeWeightValue(
options?.Vendor,
"vendor",
DefaultVendorWeight,
ceiling,
issues);
var distro = NormalizeWeightValue(
options?.Distro,
"distro",
DefaultDistroWeight,
ceiling,
issues);
var platform = NormalizeWeightValue(
options?.Platform,
"platform",
DefaultPlatformWeight,
ceiling,
issues);
var hub = NormalizeWeightValue(
options?.Hub,
"hub",
DefaultHubWeight,
ceiling,
issues);
var attestation = NormalizeWeightValue(
options?.Attestation,
"attestation",
DefaultAttestationWeight,
ceiling,
issues);
return new WeightNormalizationResult(vendor, distro, platform, hub, attestation, ceiling);
}
private static double NormalizeWeightValue(
double? value,
string fieldName,
double defaultValue,
double ceiling,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
if (value is null)
{
return defaultValue;
}
if (double.IsNaN(value.Value) || double.IsInfinity(value.Value))
{
issues.Add(new VexPolicyIssue(
$"weights.{fieldName}.invalid",
$"{fieldName} must be a finite number; default {defaultValue.ToString(CultureInfo.InvariantCulture)} applied.",
VexPolicyIssueSeverity.Warning));
return defaultValue;
}
if (value.Value < 0 || value.Value > ceiling)
{
issues.Add(new VexPolicyIssue(
$"weights.{fieldName}.range",
$"{fieldName} must be between 0 and {ceiling.ToString(CultureInfo.InvariantCulture)}; value {value.Value.ToString(CultureInfo.InvariantCulture)} was clamped.",
VexPolicyIssueSeverity.Warning));
return Math.Clamp(value.Value, 0, ceiling);
}
return value.Value;
}
private static double NormalizeWeightCeiling(double? ceiling, ImmutableArray<VexPolicyIssue>.Builder issues)
{
if (ceiling is null)
{
return VexConsensusPolicyOptions.DefaultWeightCeiling;
}
if (double.IsNaN(ceiling.Value) || double.IsInfinity(ceiling.Value) || ceiling.Value <= 0)
{
issues.Add(new VexPolicyIssue(
"weights.ceiling.invalid",
"weights.ceiling must be a positive, finite number; default ceiling applied.",
VexPolicyIssueSeverity.Warning));
return VexConsensusPolicyOptions.DefaultWeightCeiling;
}
if (ceiling.Value < 1)
{
issues.Add(new VexPolicyIssue(
"weights.ceiling.minimum",
"weights.ceiling below 1 falls back to 1 to preserve baseline behaviour.",
VexPolicyIssueSeverity.Warning));
return 1;
}
if (ceiling.Value > VexConsensusPolicyOptions.MaxSupportedCeiling)
{
issues.Add(new VexPolicyIssue(
"weights.ceiling.maximum",
$"weights.ceiling exceeded supported range; value {ceiling.Value.ToString(CultureInfo.InvariantCulture)} was clamped to {VexConsensusPolicyOptions.MaxSupportedCeiling.ToString(CultureInfo.InvariantCulture)}.",
VexPolicyIssueSeverity.Warning));
return VexConsensusPolicyOptions.MaxSupportedCeiling;
}
return ceiling.Value;
}
private static ImmutableDictionary<string, double> NormalizeOverrides(
IDictionary<string, double>? overrides,
double ceiling,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
if (overrides is null || overrides.Count == 0)
{
return ImmutableDictionary<string, double>.Empty;
}
var builder = ImmutableDictionary.CreateBuilder<string, double>(StringComparer.Ordinal);
foreach (var kvp in overrides)
{
if (string.IsNullOrWhiteSpace(kvp.Key))
{
issues.Add(new VexPolicyIssue(
"overrides.key.missing",
"Encountered provider override with empty key; ignoring entry.",
VexPolicyIssueSeverity.Warning));
continue;
}
var key = kvp.Key.Trim();
var weight = NormalizeWeightValue(
kvp.Value,
$"overrides.{key}",
DefaultVendorWeight,
ceiling,
issues);
builder[key] = weight;
}
return builder.ToImmutable();
}
private static ScoringNormalizationResult NormalizeScoring(
VexPolicyScoringOptions? options,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
var alpha = NormalizeCoefficient(
options?.Alpha,
"alpha",
VexConsensusPolicyOptions.DefaultAlpha,
issues);
var beta = NormalizeCoefficient(
options?.Beta,
"beta",
VexConsensusPolicyOptions.DefaultBeta,
issues);
return new ScoringNormalizationResult(alpha, beta);
}
private static double NormalizeCoefficient(
double? value,
string fieldName,
double defaultValue,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
if (value is null)
{
return defaultValue;
}
if (double.IsNaN(value.Value) || double.IsInfinity(value.Value))
{
issues.Add(new VexPolicyIssue(
$"scoring.{fieldName}.invalid",
$"{fieldName} coefficient must be a finite number; default {defaultValue.ToString(CultureInfo.InvariantCulture)} applied.",
VexPolicyIssueSeverity.Warning));
return defaultValue;
}
if (value.Value < 0)
{
issues.Add(new VexPolicyIssue(
$"scoring.{fieldName}.range",
$"{fieldName} cannot be negative; default {defaultValue.ToString(CultureInfo.InvariantCulture)} applied.",
VexPolicyIssueSeverity.Warning));
return defaultValue;
}
if (value.Value > VexConsensusPolicyOptions.MaxSupportedCoefficient)
{
issues.Add(new VexPolicyIssue(
$"scoring.{fieldName}.maximum",
$"{fieldName} exceeded supported range; value {value.Value.ToString(CultureInfo.InvariantCulture)} was clamped to {VexConsensusPolicyOptions.MaxSupportedCoefficient.ToString(CultureInfo.InvariantCulture)}.",
VexPolicyIssueSeverity.Warning));
return VexConsensusPolicyOptions.MaxSupportedCoefficient;
}
return value.Value;
}
private static int CompareIssues(VexPolicyIssue left, VexPolicyIssue right)
{
var severityCompare = GetSeverityRank(left.Severity).CompareTo(GetSeverityRank(right.Severity));
if (severityCompare != 0)
{
return severityCompare;
}
return string.Compare(left.Code, right.Code, StringComparison.Ordinal);
}
private static int GetSeverityRank(VexPolicyIssueSeverity severity)
=> severity switch
{
VexPolicyIssueSeverity.Error => 0,
VexPolicyIssueSeverity.Warning => 1,
_ => 2,
};
private static readonly Comparer<VexPolicyIssue> IssueComparer = Comparer<VexPolicyIssue>.Create(CompareIssues);
internal sealed record VexPolicyNormalizationResult(
VexConsensusPolicyOptions ConsensusOptions,
ImmutableArray<VexPolicyIssue> Issues);
private sealed record WeightNormalizationResult(
double Vendor,
double Distro,
double Platform,
double Hub,
double Attestation,
double Ceiling);
private sealed record ScoringNormalizationResult(double Alpha, double Beta);
}
using System.Collections.Immutable;
using System.Globalization;
using StellaOps.Excititor.Core;
namespace StellaOps.Excititor.Policy;
internal static class VexPolicyProcessing
{
private const double DefaultVendorWeight = 1.0;
private const double DefaultDistroWeight = 0.9;
private const double DefaultPlatformWeight = 0.7;
private const double DefaultHubWeight = 0.5;
private const double DefaultAttestationWeight = 0.6;
public static VexPolicyNormalizationResult Normalize(VexPolicyOptions? options)
{
var issues = ImmutableArray.CreateBuilder<VexPolicyIssue>();
var policyOptions = options ?? new VexPolicyOptions();
var normalizedWeights = NormalizeWeights(policyOptions.Weights, issues);
var overrides = NormalizeOverrides(policyOptions.ProviderOverrides, normalizedWeights.Ceiling, issues);
var scoring = NormalizeScoring(policyOptions.Scoring, issues);
var consensusOptions = new VexConsensusPolicyOptions(
policyOptions.Version ?? VexConsensusPolicyOptions.BaselineVersion,
normalizedWeights.Vendor,
normalizedWeights.Distro,
normalizedWeights.Platform,
normalizedWeights.Hub,
normalizedWeights.Attestation,
overrides,
normalizedWeights.Ceiling,
scoring.Alpha,
scoring.Beta);
var orderedIssues = issues.ToImmutable().Sort(IssueComparer);
return new VexPolicyNormalizationResult(consensusOptions, orderedIssues);
}
public static ImmutableArray<VexPolicyIssue> SortIssues(IEnumerable<VexPolicyIssue> issues)
=> issues.ToImmutableArray().Sort(IssueComparer);
private static WeightNormalizationResult NormalizeWeights(
VexPolicyWeightOptions? options,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
var ceiling = NormalizeWeightCeiling(options?.Ceiling, issues);
var vendor = NormalizeWeightValue(
options?.Vendor,
"vendor",
DefaultVendorWeight,
ceiling,
issues);
var distro = NormalizeWeightValue(
options?.Distro,
"distro",
DefaultDistroWeight,
ceiling,
issues);
var platform = NormalizeWeightValue(
options?.Platform,
"platform",
DefaultPlatformWeight,
ceiling,
issues);
var hub = NormalizeWeightValue(
options?.Hub,
"hub",
DefaultHubWeight,
ceiling,
issues);
var attestation = NormalizeWeightValue(
options?.Attestation,
"attestation",
DefaultAttestationWeight,
ceiling,
issues);
return new WeightNormalizationResult(vendor, distro, platform, hub, attestation, ceiling);
}
private static double NormalizeWeightValue(
double? value,
string fieldName,
double defaultValue,
double ceiling,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
if (value is null)
{
return defaultValue;
}
if (double.IsNaN(value.Value) || double.IsInfinity(value.Value))
{
issues.Add(new VexPolicyIssue(
$"weights.{fieldName}.invalid",
$"{fieldName} must be a finite number; default {defaultValue.ToString(CultureInfo.InvariantCulture)} applied.",
VexPolicyIssueSeverity.Warning));
return defaultValue;
}
if (value.Value < 0 || value.Value > ceiling)
{
issues.Add(new VexPolicyIssue(
$"weights.{fieldName}.range",
$"{fieldName} must be between 0 and {ceiling.ToString(CultureInfo.InvariantCulture)}; value {value.Value.ToString(CultureInfo.InvariantCulture)} was clamped.",
VexPolicyIssueSeverity.Warning));
return Math.Clamp(value.Value, 0, ceiling);
}
return value.Value;
}
private static double NormalizeWeightCeiling(double? ceiling, ImmutableArray<VexPolicyIssue>.Builder issues)
{
if (ceiling is null)
{
return VexConsensusPolicyOptions.DefaultWeightCeiling;
}
if (double.IsNaN(ceiling.Value) || double.IsInfinity(ceiling.Value) || ceiling.Value <= 0)
{
issues.Add(new VexPolicyIssue(
"weights.ceiling.invalid",
"weights.ceiling must be a positive, finite number; default ceiling applied.",
VexPolicyIssueSeverity.Warning));
return VexConsensusPolicyOptions.DefaultWeightCeiling;
}
if (ceiling.Value < 1)
{
issues.Add(new VexPolicyIssue(
"weights.ceiling.minimum",
"weights.ceiling below 1 falls back to 1 to preserve baseline behaviour.",
VexPolicyIssueSeverity.Warning));
return 1;
}
if (ceiling.Value > VexConsensusPolicyOptions.MaxSupportedCeiling)
{
issues.Add(new VexPolicyIssue(
"weights.ceiling.maximum",
$"weights.ceiling exceeded supported range; value {ceiling.Value.ToString(CultureInfo.InvariantCulture)} was clamped to {VexConsensusPolicyOptions.MaxSupportedCeiling.ToString(CultureInfo.InvariantCulture)}.",
VexPolicyIssueSeverity.Warning));
return VexConsensusPolicyOptions.MaxSupportedCeiling;
}
return ceiling.Value;
}
private static ImmutableDictionary<string, double> NormalizeOverrides(
IDictionary<string, double>? overrides,
double ceiling,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
if (overrides is null || overrides.Count == 0)
{
return ImmutableDictionary<string, double>.Empty;
}
var builder = ImmutableDictionary.CreateBuilder<string, double>(StringComparer.Ordinal);
foreach (var kvp in overrides)
{
if (string.IsNullOrWhiteSpace(kvp.Key))
{
issues.Add(new VexPolicyIssue(
"overrides.key.missing",
"Encountered provider override with empty key; ignoring entry.",
VexPolicyIssueSeverity.Warning));
continue;
}
var key = kvp.Key.Trim();
var weight = NormalizeWeightValue(
kvp.Value,
$"overrides.{key}",
DefaultVendorWeight,
ceiling,
issues);
builder[key] = weight;
}
return builder.ToImmutable();
}
private static ScoringNormalizationResult NormalizeScoring(
VexPolicyScoringOptions? options,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
var alpha = NormalizeCoefficient(
options?.Alpha,
"alpha",
VexConsensusPolicyOptions.DefaultAlpha,
issues);
var beta = NormalizeCoefficient(
options?.Beta,
"beta",
VexConsensusPolicyOptions.DefaultBeta,
issues);
return new ScoringNormalizationResult(alpha, beta);
}
private static double NormalizeCoefficient(
double? value,
string fieldName,
double defaultValue,
ImmutableArray<VexPolicyIssue>.Builder issues)
{
if (value is null)
{
return defaultValue;
}
if (double.IsNaN(value.Value) || double.IsInfinity(value.Value))
{
issues.Add(new VexPolicyIssue(
$"scoring.{fieldName}.invalid",
$"{fieldName} coefficient must be a finite number; default {defaultValue.ToString(CultureInfo.InvariantCulture)} applied.",
VexPolicyIssueSeverity.Warning));
return defaultValue;
}
if (value.Value < 0)
{
issues.Add(new VexPolicyIssue(
$"scoring.{fieldName}.range",
$"{fieldName} cannot be negative; default {defaultValue.ToString(CultureInfo.InvariantCulture)} applied.",
VexPolicyIssueSeverity.Warning));
return defaultValue;
}
if (value.Value > VexConsensusPolicyOptions.MaxSupportedCoefficient)
{
issues.Add(new VexPolicyIssue(
$"scoring.{fieldName}.maximum",
$"{fieldName} exceeded supported range; value {value.Value.ToString(CultureInfo.InvariantCulture)} was clamped to {VexConsensusPolicyOptions.MaxSupportedCoefficient.ToString(CultureInfo.InvariantCulture)}.",
VexPolicyIssueSeverity.Warning));
return VexConsensusPolicyOptions.MaxSupportedCoefficient;
}
return value.Value;
}
private static int CompareIssues(VexPolicyIssue left, VexPolicyIssue right)
{
var severityCompare = GetSeverityRank(left.Severity).CompareTo(GetSeverityRank(right.Severity));
if (severityCompare != 0)
{
return severityCompare;
}
return string.Compare(left.Code, right.Code, StringComparison.Ordinal);
}
private static int GetSeverityRank(VexPolicyIssueSeverity severity)
=> severity switch
{
VexPolicyIssueSeverity.Error => 0,
VexPolicyIssueSeverity.Warning => 1,
_ => 2,
};
private static readonly Comparer<VexPolicyIssue> IssueComparer = Comparer<VexPolicyIssue>.Create(CompareIssues);
internal sealed record VexPolicyNormalizationResult(
VexConsensusPolicyOptions ConsensusOptions,
ImmutableArray<VexPolicyIssue> Issues);
private sealed record WeightNormalizationResult(
double Vendor,
double Distro,
double Platform,
double Hub,
double Attestation,
double Ceiling);
private sealed record ScoringNormalizationResult(double Alpha, double Beta);
}

View File

@@ -1,24 +1,24 @@
using System.Collections.Generic;
using System.Diagnostics.Metrics;
namespace StellaOps.Excititor.Policy;
internal static class VexPolicyTelemetry
{
private const string MeterName = "StellaOps.Excititor.Policy";
private const string MeterVersion = "1.0.0";
private static readonly Meter Meter = new(MeterName, MeterVersion);
private static readonly Counter<long> PolicyReloads = Meter.CreateCounter<long>("vex.policy.reloads", unit: "events");
public static void RecordReload(string revisionId, string version, int issueCount)
{
var tags = new KeyValuePair<string, object?>[]
{
new("revision", revisionId),
new("version", version),
new("issues", issueCount),
};
PolicyReloads.Add(1, tags);
}
}
using System.Collections.Generic;
using System.Diagnostics.Metrics;
namespace StellaOps.Excititor.Policy;
internal static class VexPolicyTelemetry
{
private const string MeterName = "StellaOps.Excititor.Policy";
private const string MeterVersion = "1.0.0";
private static readonly Meter Meter = new(MeterName, MeterVersion);
private static readonly Counter<long> PolicyReloads = Meter.CreateCounter<long>("vex.policy.reloads", unit: "events");
public static void RecordReload(string revisionId, string version, int issueCount)
{
var tags = new KeyValuePair<string, object?>[]
{
new("revision", revisionId),
new("version", version),
new("issues", issueCount),
};
PolicyReloads.Add(1, tags);
}
}