206 lines
5.5 KiB
C#
206 lines
5.5 KiB
C#
// 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;
|
|
|
|
/// <summary>
|
|
/// Interface for providers that contribute confidence factors.
|
|
/// </summary>
|
|
public interface IConfidenceFactorProvider
|
|
{
|
|
/// <summary>
|
|
/// The type of confidence factor this provider produces.
|
|
/// </summary>
|
|
ConfidenceFactorType Type { get; }
|
|
|
|
/// <summary>
|
|
/// Compute a confidence factor from available context.
|
|
/// Returns null if insufficient data to compute.
|
|
/// </summary>
|
|
ConfidenceFactor? ComputeFactor(
|
|
ConfidenceFactorContext context,
|
|
ConfidenceFactorOptions options);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Context for confidence factor computation.
|
|
/// </summary>
|
|
public sealed record ConfidenceFactorContext
|
|
{
|
|
/// <summary>
|
|
/// VEX trust status from signature verification.
|
|
/// </summary>
|
|
public VexTrustStatus? VexTrustStatus { get; init; }
|
|
|
|
/// <summary>
|
|
/// Environment (production, staging, development).
|
|
/// </summary>
|
|
public string? Environment { get; init; }
|
|
|
|
/// <summary>
|
|
/// Tenant identifier.
|
|
/// </summary>
|
|
public string? TenantId { get; init; }
|
|
|
|
/// <summary>
|
|
/// CVE or vulnerability identifier.
|
|
/// </summary>
|
|
public string? VulnerabilityId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Product/component identifier.
|
|
/// </summary>
|
|
public string? ProductId { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Options for confidence factor computation.
|
|
/// </summary>
|
|
public sealed record ConfidenceFactorOptions
|
|
{
|
|
/// <summary>
|
|
/// Weight to assign to VEX trust factor.
|
|
/// </summary>
|
|
public decimal VexTrustWeight { get; init; } = 0.20m;
|
|
|
|
/// <summary>
|
|
/// Minimum trust score to contribute positively.
|
|
/// </summary>
|
|
public decimal MinTrustScoreContribution { get; init; } = 0.30m;
|
|
|
|
/// <summary>
|
|
/// Bonus for signature verification.
|
|
/// </summary>
|
|
public decimal SignatureVerifiedBonus { get; init; } = 0.10m;
|
|
|
|
/// <summary>
|
|
/// Bonus for Rekor transparency.
|
|
/// </summary>
|
|
public decimal TransparencyBonus { get; init; } = 0.05m;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes VEX trust confidence factor from signature verification results.
|
|
/// </summary>
|
|
public sealed class VexTrustConfidenceFactorProvider : IConfidenceFactorProvider
|
|
{
|
|
public ConfidenceFactorType Type => ConfidenceFactorType.Vex;
|
|
|
|
/// <inheritdoc />
|
|
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<string>
|
|
{
|
|
$"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<string> BuildEvidenceDigests(VexTrustStatus status)
|
|
{
|
|
var digests = new List<string>();
|
|
|
|
// 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;
|
|
}
|
|
}
|