using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; using StellaOps.Concelier.Models; namespace StellaOps.Concelier.Core.Unknown; /// /// Default implementation that derives unknown-state markers from canonical advisories. /// public sealed class UnknownStateLedger : IUnknownStateLedger { private static readonly ImmutableHashSet ImpactStatuses = ImmutableHashSet.Create( StringComparer.Ordinal, AffectedPackageStatusCatalog.KnownAffected, AffectedPackageStatusCatalog.Affected, AffectedPackageStatusCatalog.UnderInvestigation, AffectedPackageStatusCatalog.Pending, AffectedPackageStatusCatalog.Unknown); private static readonly ImmutableHashSet FixStatuses = ImmutableHashSet.Create( StringComparer.Ordinal, AffectedPackageStatusCatalog.Fixed, AffectedPackageStatusCatalog.FirstFixed, AffectedPackageStatusCatalog.Mitigated); private static readonly ImmutableDictionary MarkerSeeds = new Dictionary(StringComparer.Ordinal) { [UnknownStateMarkerKinds.UnknownVulnerabilityRange] = new UnknownMarkerSeed(0.8, "high"), [UnknownStateMarkerKinds.UnknownOrigin] = new UnknownMarkerSeed(0.6, "medium"), [UnknownStateMarkerKinds.AmbiguousFix] = new UnknownMarkerSeed(0.45, "medium"), }.ToImmutableDictionary(StringComparer.Ordinal); private readonly IUnknownStateRepository _repository; private readonly TimeProvider _timeProvider; public UnknownStateLedger(IUnknownStateRepository repository, TimeProvider? timeProvider = null) { _repository = repository ?? throw new ArgumentNullException(nameof(repository)); _timeProvider = timeProvider ?? TimeProvider.System; } public async ValueTask RecordAsync( UnknownStateLedgerRequest request, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(request); var recordedAt = _timeProvider.GetUtcNow(); var markers = EvaluateMarkers(request.Advisory, request.AsOf, recordedAt); await _repository.UpsertAsync(request.VulnerabilityKey, markers, cancellationToken).ConfigureAwait(false); return new UnknownStateLedgerResult(request.VulnerabilityKey, request.AsOf, markers); } public ValueTask> GetByVulnerabilityAsync( string vulnerabilityKey, CancellationToken cancellationToken) { ArgumentException.ThrowIfNullOrWhiteSpace(vulnerabilityKey); var normalizedKey = vulnerabilityKey.Trim().ToLowerInvariant(); return _repository.GetByVulnerabilityAsync(normalizedKey, cancellationToken); } private static ImmutableArray EvaluateMarkers( Advisory advisory, DateTimeOffset observedAt, DateTimeOffset recordedAt) { var builder = ImmutableArray.CreateBuilder(initialCapacity: 3); if (advisory is not null) { if (TryCreateUnknownVulnerabilityRangeMarker(advisory, observedAt, recordedAt, out var unknownRange)) { builder.Add(unknownRange); } if (TryCreateUnknownOriginMarker(advisory, observedAt, recordedAt, out var unknownOrigin)) { builder.Add(unknownOrigin); } if (TryCreateAmbiguousFixMarker(advisory, observedAt, recordedAt, out var ambiguousFix)) { builder.Add(ambiguousFix); } } if (builder.Count == 0) { return ImmutableArray.Empty; } builder.Sort(static (left, right) => StringComparer.Ordinal.Compare(left.Marker, right.Marker)); return builder.ToImmutable(); } private static bool TryCreateUnknownVulnerabilityRangeMarker( Advisory advisory, DateTimeOffset observedAt, DateTimeOffset recordedAt, out UnknownStateSnapshot snapshot) { snapshot = null!; if (advisory.AffectedPackages.IsDefaultOrEmpty) { return false; } var lackingPackages = 0; foreach (var package in advisory.AffectedPackages) { if (package is null) { continue; } if (!HasImpactStatus(package)) { continue; } if (!HasConcreteRange(package)) { lackingPackages++; } } if (lackingPackages == 0) { return false; } var seed = MarkerSeeds[UnknownStateMarkerKinds.UnknownVulnerabilityRange]; var evidence = lackingPackages == 1 ? "1 affected package lacks explicit version ranges." : $"{lackingPackages} affected packages lack explicit version ranges."; snapshot = new UnknownStateSnapshot( UnknownStateMarkerKinds.UnknownVulnerabilityRange, seed.Confidence, seed.Band, observedAt, recordedAt, evidence); return true; } private static bool TryCreateUnknownOriginMarker( Advisory advisory, DateTimeOffset observedAt, DateTimeOffset recordedAt, out UnknownStateSnapshot snapshot) { snapshot = null!; if (ContainsKnownProvenance(advisory.Provenance)) { return false; } var seed = MarkerSeeds[UnknownStateMarkerKinds.UnknownOrigin]; var evidence = advisory.Provenance.IsDefaultOrEmpty ? "Advisory provenance is missing; falling back to inferred sources." : "All advisory provenance sources resolve to 'unknown'."; snapshot = new UnknownStateSnapshot( UnknownStateMarkerKinds.UnknownOrigin, seed.Confidence, seed.Band, observedAt, recordedAt, evidence); return true; } private static bool TryCreateAmbiguousFixMarker( Advisory advisory, DateTimeOffset observedAt, DateTimeOffset recordedAt, out UnknownStateSnapshot snapshot) { snapshot = null!; if (advisory.AffectedPackages.IsDefaultOrEmpty) { return false; } var ambiguousPackages = 0; foreach (var package in advisory.AffectedPackages) { if (package is null) { continue; } if (!package.Statuses.IsDefaultOrEmpty && package.Statuses.Any(status => FixStatuses.Contains(status.Status))) { var hasFixedRange = package.VersionRanges.Any(static range => !string.IsNullOrWhiteSpace(range.FixedVersion)); if (!hasFixedRange) { ambiguousPackages++; } } } if (ambiguousPackages == 0) { return false; } var seed = MarkerSeeds[UnknownStateMarkerKinds.AmbiguousFix]; var evidence = ambiguousPackages == 1 ? "Fix status published without explicit fixed version details." : $"Fix status published without explicit fixed versions for {ambiguousPackages} packages."; snapshot = new UnknownStateSnapshot( UnknownStateMarkerKinds.AmbiguousFix, seed.Confidence, seed.Band, observedAt, recordedAt, evidence); return true; } private static bool HasImpactStatus(AffectedPackage package) { if (package.Statuses.IsDefaultOrEmpty) { return false; } foreach (var status in package.Statuses) { if (status is null) { continue; } if (ImpactStatuses.Contains(status.Status)) { return true; } } return false; } private static bool HasConcreteRange(AffectedPackage package) { if (package.VersionRanges.IsDefaultOrEmpty) { return false; } foreach (var range in package.VersionRanges) { if (range is null) { continue; } if (!string.IsNullOrWhiteSpace(range.IntroducedVersion) || !string.IsNullOrWhiteSpace(range.FixedVersion) || !string.IsNullOrWhiteSpace(range.LastAffectedVersion) || !string.IsNullOrWhiteSpace(range.RangeExpression)) { return true; } } return false; } private static bool ContainsKnownProvenance(ImmutableArray provenance) { if (provenance.IsDefaultOrEmpty) { return false; } foreach (var entry in provenance) { if (entry is null) { continue; } if (IsKnownSource(entry.Source)) { return true; } } return false; } private static bool IsKnownSource(string? source) => !string.IsNullOrWhiteSpace(source) && !string.Equals(source, "unknown", StringComparison.OrdinalIgnoreCase); private readonly record struct UnknownMarkerSeed(double Confidence, string Band); }