Files
git.stella-ops.org/docs-archived/product-advisories/22-Dec-2025 - Getting Distro Backport Logic Right.md
2026-01-05 16:02:11 +02:00

4.3 KiB

ARCHIVED

Archived: 2025-12-22 Reason: Gap analysis complete. Recommendations incorporated into sprints and documentation.

Implementation Artifacts:

  • SPRINT_2000_0003_0001: Alpine connector and APK comparator
  • SPRINT_2000_0003_0002: Comprehensive distro version tests (50-100 per distro)
  • SPRINT_4000_0002_0001: Backport UX explainability ("Compared with" badge, "Why Fixed" popover)
  • SPRINT_6000_SUMMARY.md: Updated to reference existing Concelier comparators
  • src/Concelier/AGENTS.md: Added distro backport version handling section

Existing Implementations Validated:

  • src/Concelier/__Libraries/StellaOps.Concelier.Merge/Comparers/Nevra.cs (RPM)
  • src/Concelier/__Libraries/StellaOps.Concelier.Merge/Comparers/DebianEvr.cs (Debian/Ubuntu)
  • Distro connectors: Debian, Ubuntu, RedHat, SUSE

Here's a quick, practical heads-up on patch-aware backport handling so your vulnerability verdicts don't go sideways.

Package versions concept diagram

Why this matters

Distros often backport fixes without bumping the upstream version. If you compare versions with a generic SemVer library, you can mislabel fixed builds as vulnerable (or the reverse).

Use distro-native comparators (not SemVer)

  • RPM (RHEL/CentOS/Fedora/openSUSE): compare using EVR (epoch:version-release) via rpmvercmp. Tilde ~ sorts before anything; releases matter (e.g., 1.2-3.el9_2 > 1.2-3).
  • Debian/Ubuntu: compare epoch >> upstream_version >> debian_revision using dpkg --compare-versions rules. Tilde ~ sorts lower than empty, so 2.0~rc1 < 2.0.
  • Alpine (APK): follows its own comparator; treat -r (pkgrel) as part of ordering, similar in spirit to RPM release.

Practical rules for your scanner (Stella Ops / Feedser -> Vexer)

  1. Normalize the package coordinate

    • RPM: name:evr.arch (epoch default 0 if missing).
    • DEB: name:epoch:upstream_version-debian_revision arch.
    • Keep the distro release/revision; it encodes backports.
  2. Compare with native engines

    • On Linux hosts/containers, call the system tool when possible:

      • RPM: rpm --qf '%{EPOCH}:%{VERSION}-%{RELEASE}\n' -q <pkg> then use rpmdev-vercmp/rpmvercmp.
      • DEB/Ubuntu: dpkg-query -W -f='${Version}\n' <pkg> and dpkg --compare-versions.
    • In offline analysis, embed battle-tested comparators (ports of rpmvercmp and dpkg logic) in your evaluator.

  3. Model advisories with distro ranges

    • Store per-ecosystem fixed ranges:

      • RPM example: fixed >= 2:1.4.3-5.el9_3
      • DEB example: fixed >= 1:1.4.3-5+deb12u2
    • Do not rewrite to SemVer; keep native forms.

  4. VEX/decisioning

    • When upstream says "fixed in 1.4.4" but distro claims fixed in 1.4.3-5~deb12u2, prefer distro channel if source is trusted.
    • Record evidence: source (DSA/RHSA/USN), comparator used, installed EVR/DEB version, fixed threshold, and result. Attach to the verdict.
  5. Edge cases to test

    • Epoch jumps: 1:1.2-1 > 0:9.9-9.
    • Tilde pre-releases: 2.0~rc1 < 2.0.
    • Release qualifiers: 1.2-3.el9_2 < 1.2-3.el9_3.
    • Rebuilds/backports: 1.2-3ubuntu0.1 vs 1.2-3.

Minimal implementation sketch (C#)

  • Strategy pattern: IVersionComparator with implementations RpmComparator, DpkgComparator, ApkComparator.

  • Selector by package source (rpmdb, dpkg-status, apk info).

  • Evidence struct:

    record VersionVerdict(
      string Pkg, string Distro, string Installed, string Fixed,
      string Comparator, bool IsFixed, string EvidenceSource, string[] ProofLines);
    
  • Fallback: If native comparator unavailable, use embedded ports of rpmvercmp and Debian's algorithm; never SemVer.

CI tests you should pin

  • A table-driven test set with 50-100 cases covering epochs, tildes, and distro revisions.
  • Golden files per distro to prevent regressions.
  • Cross-check installed values from real images (e.g., ubi9, debian:12, ubuntu:22.04, alpine:3.20).

UX nudge

  • In the UI, show "Compared with: RPM EVR / dpkg rules" and link the exact fixed threshold that matched. Provide a "why fixed" popover showing the string compare steps.

If you like, I can drop in ready-to-use C# comparators (rpmvercmp/dpkg) and a test corpus so you can wire this straight into Feedser/Vexer.