// VexTrustConfidenceFactorProvider - Confidence factor from VEX trust data // Part of SPRINT_1227_0004_0003: VexTrustGate Policy Integration using StellaOps.Policy.Confidence.Models; using StellaOps.Policy.Engine.Gates; using System; using System.Collections.Generic; namespace StellaOps.Policy.Engine.Confidence; /// /// Interface for providers that contribute confidence factors. /// public interface IConfidenceFactorProvider { /// /// The type of confidence factor this provider produces. /// ConfidenceFactorType Type { get; } /// /// Compute a confidence factor from available context. /// Returns null if insufficient data to compute. /// ConfidenceFactor? ComputeFactor( ConfidenceFactorContext context, ConfidenceFactorOptions options); } /// /// Context for confidence factor computation. /// public sealed record ConfidenceFactorContext { /// /// VEX trust status from signature verification. /// public VexTrustStatus? VexTrustStatus { get; init; } /// /// Environment (production, staging, development). /// public string? Environment { get; init; } /// /// Tenant identifier. /// public string? TenantId { get; init; } /// /// CVE or vulnerability identifier. /// public string? VulnerabilityId { get; init; } /// /// Product/component identifier. /// public string? ProductId { get; init; } } /// /// Options for confidence factor computation. /// public sealed record ConfidenceFactorOptions { /// /// Weight to assign to VEX trust factor. /// public decimal VexTrustWeight { get; init; } = 0.20m; /// /// Minimum trust score to contribute positively. /// public decimal MinTrustScoreContribution { get; init; } = 0.30m; /// /// Bonus for signature verification. /// public decimal SignatureVerifiedBonus { get; init; } = 0.10m; /// /// Bonus for Rekor transparency. /// public decimal TransparencyBonus { get; init; } = 0.05m; } /// /// Computes VEX trust confidence factor from signature verification results. /// public sealed class VexTrustConfidenceFactorProvider : IConfidenceFactorProvider { public ConfidenceFactorType Type => ConfidenceFactorType.Vex; /// public ConfidenceFactor? ComputeFactor( ConfidenceFactorContext context, ConfidenceFactorOptions options) { ArgumentNullException.ThrowIfNull(context); ArgumentNullException.ThrowIfNull(options); var trustStatus = context.VexTrustStatus; // No trust status means we can't contribute a factor if (trustStatus is null) { return null; } var score = trustStatus.TrustScore; var tier = ComputeTier(score); // Apply bonuses for verification and transparency var adjustedScore = score; if (trustStatus.SignatureVerified == true) { adjustedScore += options.SignatureVerifiedBonus; } if (trustStatus.RekorLogIndex.HasValue) { adjustedScore += options.TransparencyBonus; } // Clamp to [0, 1] adjustedScore = Math.Clamp(adjustedScore, 0m, 1m); return new ConfidenceFactor { Type = ConfidenceFactorType.Vex, Weight = options.VexTrustWeight, RawValue = adjustedScore, Reason = BuildReason(trustStatus, tier), EvidenceDigests = BuildEvidenceDigests(trustStatus) }; } private static string ComputeTier(decimal score) { return score switch { >= 0.9m => "VeryHigh", >= 0.7m => "High", >= 0.5m => "Medium", >= 0.3m => "Low", _ => "VeryLow" }; } private static string BuildReason(VexTrustStatus status, string tier) { var parts = new List { $"VEX trust: {tier} ({status.TrustScore:P0})" }; if (!string.IsNullOrEmpty(status.IssuerName)) { parts.Add($"issuer: {status.IssuerName}"); } if (status.SignatureVerified == true) { parts.Add("signature verified"); if (!string.IsNullOrEmpty(status.SignatureMethod)) { parts.Add($"method: {status.SignatureMethod}"); } } if (status.RekorLogIndex.HasValue) { parts.Add($"Rekor: #{status.RekorLogIndex}"); } if (!string.IsNullOrEmpty(status.Freshness)) { parts.Add($"freshness: {status.Freshness}"); } return string.Join("; ", parts); } private static IReadOnlyList BuildEvidenceDigests(VexTrustStatus status) { var digests = new List(); // Add Rekor log info as an evidence reference if (!string.IsNullOrEmpty(status.RekorLogId) && status.RekorLogIndex.HasValue) { digests.Add($"rekor:{status.RekorLogId}@{status.RekorLogIndex}"); } // Add issuer reference if (!string.IsNullOrEmpty(status.IssuerId)) { digests.Add($"issuer:{status.IssuerId}"); } return digests; } }