186 lines
8.3 KiB
C#
186 lines
8.3 KiB
C#
// -----------------------------------------------------------------------------
|
|
// DistroDerivative.cs
|
|
// Sprint: SPRINT_20251230_001_BE_backport_resolver (BP-301, BP-302, BP-303, BP-304)
|
|
// Task: Create DistroDerivativeMapping model for cross-distro OVAL/CSAF evidence
|
|
// -----------------------------------------------------------------------------
|
|
|
|
using System.Collections.Frozen;
|
|
using System.Collections.Immutable;
|
|
|
|
namespace StellaOps.DistroIntel;
|
|
|
|
/// <summary>
|
|
/// Confidence level for derivative distro mappings.
|
|
/// Determines the confidence penalty applied when using evidence from a derivative.
|
|
/// </summary>
|
|
public enum DerivativeConfidence
|
|
{
|
|
/// <summary>
|
|
/// High confidence - ABI-compatible rebuilds.
|
|
/// Examples: AlmaLinux/Rocky → RHEL, CentOS → RHEL
|
|
/// Confidence multiplier: 0.95
|
|
/// </summary>
|
|
High,
|
|
|
|
/// <summary>
|
|
/// Medium confidence - Modified derivatives with some customizations.
|
|
/// Examples: Linux Mint → Ubuntu, Ubuntu → Debian
|
|
/// Confidence multiplier: 0.80
|
|
/// </summary>
|
|
Medium
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents a relationship between a canonical (parent) distro and a derivative.
|
|
/// Used for Tier 1 evidence fallback when native OVAL/CSAF is unavailable.
|
|
/// </summary>
|
|
/// <param name="CanonicalDistro">The parent/upstream distro identifier (e.g., "rhel", "debian").</param>
|
|
/// <param name="DerivativeDistro">The derivative distro identifier (e.g., "almalinux", "ubuntu").</param>
|
|
/// <param name="MajorRelease">The major release version for which this mapping applies.</param>
|
|
/// <param name="Confidence">Confidence level of the derivative relationship.</param>
|
|
public sealed record DistroDerivative(
|
|
string CanonicalDistro,
|
|
string DerivativeDistro,
|
|
int MajorRelease,
|
|
DerivativeConfidence Confidence);
|
|
|
|
/// <summary>
|
|
/// Static registry of distro derivative mappings for cross-distro evidence sharing.
|
|
/// </summary>
|
|
public static class DistroMappings
|
|
{
|
|
/// <summary>
|
|
/// All known distro derivative relationships.
|
|
/// Maps parent distros to their derivatives for OVAL/CSAF fallback.
|
|
/// </summary>
|
|
public static readonly ImmutableArray<DistroDerivative> Derivatives =
|
|
[
|
|
// RHEL family - High confidence (ABI-compatible rebuilds)
|
|
new DistroDerivative("rhel", "almalinux", 8, DerivativeConfidence.High),
|
|
new DistroDerivative("rhel", "almalinux", 9, DerivativeConfidence.High),
|
|
new DistroDerivative("rhel", "almalinux", 10, DerivativeConfidence.High),
|
|
new DistroDerivative("rhel", "rocky", 8, DerivativeConfidence.High),
|
|
new DistroDerivative("rhel", "rocky", 9, DerivativeConfidence.High),
|
|
new DistroDerivative("rhel", "rocky", 10, DerivativeConfidence.High),
|
|
new DistroDerivative("rhel", "centos", 7, DerivativeConfidence.High),
|
|
new DistroDerivative("rhel", "centos", 8, DerivativeConfidence.High), // CentOS 8 (EOL)
|
|
new DistroDerivative("rhel", "oracle", 7, DerivativeConfidence.High),
|
|
new DistroDerivative("rhel", "oracle", 8, DerivativeConfidence.High),
|
|
new DistroDerivative("rhel", "oracle", 9, DerivativeConfidence.High),
|
|
|
|
// Debian family - Medium confidence (modified derivatives)
|
|
new DistroDerivative("debian", "ubuntu", 10, DerivativeConfidence.Medium), // Debian 10 -> Ubuntu derivation
|
|
new DistroDerivative("debian", "ubuntu", 11, DerivativeConfidence.Medium), // Debian 11 (Bullseye)
|
|
new DistroDerivative("debian", "ubuntu", 12, DerivativeConfidence.Medium), // Debian 12 (Bookworm)
|
|
|
|
// Ubuntu derivatives - Medium confidence
|
|
new DistroDerivative("ubuntu", "linuxmint", 20, DerivativeConfidence.Medium), // Ubuntu 20.04 base
|
|
new DistroDerivative("ubuntu", "linuxmint", 21, DerivativeConfidence.Medium), // Ubuntu 21.04 base
|
|
new DistroDerivative("ubuntu", "linuxmint", 22, DerivativeConfidence.Medium), // Ubuntu 22.04 base
|
|
new DistroDerivative("ubuntu", "pop", 20, DerivativeConfidence.Medium), // Pop!_OS
|
|
new DistroDerivative("ubuntu", "pop", 22, DerivativeConfidence.Medium),
|
|
|
|
// SUSE family
|
|
new DistroDerivative("sles", "opensuse-leap", 15, DerivativeConfidence.High),
|
|
];
|
|
|
|
private static readonly FrozenDictionary<(string, int), ImmutableArray<DistroDerivative>> _byCanonicalIndex =
|
|
Derivatives
|
|
.GroupBy(d => (d.CanonicalDistro.ToLowerInvariant(), d.MajorRelease))
|
|
.ToFrozenDictionary(
|
|
g => g.Key,
|
|
g => g.ToImmutableArray());
|
|
|
|
private static readonly FrozenDictionary<(string, int), DistroDerivative?> _byDerivativeIndex =
|
|
Derivatives
|
|
.ToFrozenDictionary(
|
|
d => (d.DerivativeDistro.ToLowerInvariant(), d.MajorRelease),
|
|
d => (DistroDerivative?)d);
|
|
|
|
/// <summary>
|
|
/// Finds derivatives for a canonical (parent) distro at a specific major release.
|
|
/// Use this to find alternative evidence sources when native OVAL/CSAF is unavailable.
|
|
/// </summary>
|
|
/// <param name="canonicalDistro">The canonical distro identifier (e.g., "rhel").</param>
|
|
/// <param name="majorRelease">The major release version.</param>
|
|
/// <returns>Matching derivative mappings, ordered by confidence (High first).</returns>
|
|
/// <example>
|
|
/// var derivatives = DistroMappings.FindDerivativesFor("rhel", 9);
|
|
/// // Returns: [(rhel, almalinux, 9, High), (rhel, rocky, 9, High), (rhel, oracle, 9, High)]
|
|
/// </example>
|
|
public static IEnumerable<DistroDerivative> FindDerivativesFor(string canonicalDistro, int majorRelease)
|
|
{
|
|
var key = (canonicalDistro.ToLowerInvariant(), majorRelease);
|
|
if (_byCanonicalIndex.TryGetValue(key, out var derivatives))
|
|
{
|
|
return derivatives.OrderByDescending(d => d.Confidence);
|
|
}
|
|
return [];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the canonical (parent) distro for a derivative distro.
|
|
/// Use this to map a derivative back to its upstream source.
|
|
/// </summary>
|
|
/// <param name="derivativeDistro">The derivative distro identifier (e.g., "almalinux").</param>
|
|
/// <param name="majorRelease">The major release version.</param>
|
|
/// <returns>The canonical mapping if found, null otherwise.</returns>
|
|
/// <example>
|
|
/// var canonical = DistroMappings.FindCanonicalFor("almalinux", 9);
|
|
/// // Returns: (rhel, almalinux, 9, High)
|
|
/// </example>
|
|
public static DistroDerivative? FindCanonicalFor(string derivativeDistro, int majorRelease)
|
|
{
|
|
var key = (derivativeDistro.ToLowerInvariant(), majorRelease);
|
|
return _byDerivativeIndex.GetValueOrDefault(key);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the confidence multiplier for a derivative relationship.
|
|
/// Apply this to the base confidence when using derivative evidence.
|
|
/// </summary>
|
|
/// <param name="confidence">The derivative confidence level.</param>
|
|
/// <returns>Multiplier value (0.95 for High, 0.80 for Medium).</returns>
|
|
public static decimal GetConfidenceMultiplier(DerivativeConfidence confidence)
|
|
{
|
|
return confidence switch
|
|
{
|
|
DerivativeConfidence.High => 0.95m,
|
|
DerivativeConfidence.Medium => 0.80m,
|
|
_ => 0.70m // Unknown - conservative
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a distro is a known canonical (parent) distro.
|
|
/// </summary>
|
|
/// <param name="distro">The distro identifier to check.</param>
|
|
/// <returns>True if the distro is a known canonical distro.</returns>
|
|
public static bool IsCanonicalDistro(string distro)
|
|
{
|
|
var lower = distro.ToLowerInvariant();
|
|
return lower is "rhel" or "debian" or "ubuntu" or "sles" or "alpine";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Normalizes a distro name to its canonical form.
|
|
/// </summary>
|
|
/// <param name="distro">The distro name to normalize.</param>
|
|
/// <returns>Lowercase canonical form.</returns>
|
|
public static string NormalizeDistroName(string distro)
|
|
{
|
|
var lower = distro.ToLowerInvariant();
|
|
return lower switch
|
|
{
|
|
"redhat" or "red hat" or "red-hat" => "rhel",
|
|
"alma" or "almalinux-os" => "almalinux",
|
|
"rockylinux" or "rocky-linux" => "rocky",
|
|
"oracle linux" or "oraclelinux" => "oracle",
|
|
"opensuse" or "opensuse-tumbleweed" => "opensuse-leap",
|
|
"mint" => "linuxmint",
|
|
"popos" or "pop_os" => "pop",
|
|
_ => lower
|
|
};
|
|
}
|
|
}
|