save progress
This commit is contained in:
185
src/__Libraries/StellaOps.DistroIntel/DistroDerivative.cs
Normal file
185
src/__Libraries/StellaOps.DistroIntel/DistroDerivative.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<RootNamespace>StellaOps.DistroIntel</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user