// SPDX-License-Identifier: BUSL-1.1 // Sprint: SPRINT_4000_0002_0001 // Task: T1 - Extend Findings API Response with version comparison metadata using System.Collections.Immutable; using System.Text.Json.Serialization; namespace StellaOps.Scanner.Evidence.Models; /// /// Evidence of version comparison used to determine vulnerability status. /// Provides explainability for backport detection logic. /// public sealed record VersionComparisonEvidence { /// /// Comparator algorithm used (rpm-evr, dpkg, apk, semver). /// [JsonPropertyName("comparator")] public required string Comparator { get; init; } /// /// Installed version in native format. /// [JsonPropertyName("installedVersion")] public required string InstalledVersion { get; init; } /// /// Fixed version threshold from advisory. /// [JsonPropertyName("fixedVersion")] public required string FixedVersion { get; init; } /// /// Whether the installed version is >= fixed. /// [JsonPropertyName("isFixed")] public required bool IsFixed { get; init; } /// /// Human-readable proof lines showing comparison steps. /// [JsonPropertyName("proofLines")] public ImmutableArray ProofLines { get; init; } = []; /// /// Advisory source (DSA-1234, RHSA-2025:1234, USN-1234-1). /// [JsonPropertyName("advisorySource")] public string? AdvisorySource { get; init; } /// /// Creates VersionComparisonEvidence from a version comparison result. /// /// The comparator type identifier. /// The installed version string. /// The fixed version threshold. /// The comparison result (negative if installed < fixed). /// Human-readable comparison steps. /// Optional advisory identifier. public static VersionComparisonEvidence Create( string comparator, string installedVersion, string fixedVersion, int comparisonResult, ImmutableArray proofLines, string? advisorySource = null) { return new VersionComparisonEvidence { Comparator = comparator, InstalledVersion = installedVersion, FixedVersion = fixedVersion, IsFixed = comparisonResult >= 0, // installed >= fixed means fixed ProofLines = proofLines, AdvisorySource = advisorySource }; } }