add sprint for improved backported CVE patches
This commit is contained in:
678
docs/implplan/SPRINT_20251230_001_BE_backport_resolver_DESIGN.md
Normal file
678
docs/implplan/SPRINT_20251230_001_BE_backport_resolver_DESIGN.md
Normal file
@@ -0,0 +1,678 @@
|
|||||||
|
# Backport Resolver Tiered Evidence - Implementation Design
|
||||||
|
**Sprint:** SPRINT_20251230_001_BE
|
||||||
|
**Version:** 1.0
|
||||||
|
**Last Updated:** 2025-12-30
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
1. [Architecture Overview](#architecture-overview)
|
||||||
|
2. [Component Design](#component-design)
|
||||||
|
3. [Data Models](#data-models)
|
||||||
|
4. [Algorithms](#algorithms)
|
||||||
|
5. [Integration Points](#integration-points)
|
||||||
|
6. [Security & Compliance](#security--compliance)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Architecture Overview
|
||||||
|
|
||||||
|
### 1.1 Current State
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
BackportStatusService
|
||||||
|
|
||||||
|
EvalPatchedStatusAsync()
|
||||||
|
GetRulesAsync() from repository
|
||||||
|
EvaluateBoundaryRules() [STRING COMPARE ]
|
||||||
|
EvaluateRangeRules() [RETURNS UNKNOWN ]
|
||||||
|
Return verdict
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Consumes rules from
|
||||||
|
|
||||||
|
|
||||||
|
IFixRuleRepository
|
||||||
|
(OVAL/CSAF/Changelog rules)
|
||||||
|
- Only native distro
|
||||||
|
- No derivative mapping
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
**Problems:**
|
||||||
|
- String comparison fails for version semantics (epoch, tildes, etc.)
|
||||||
|
- RangeRule logic not implemented always returns Unknown
|
||||||
|
- No cross-distro evidence reuse (AlmaLinux OVAL for RHEL)
|
||||||
|
- No bug ID CVE resolution
|
||||||
|
|
||||||
|
### 1.2 Target State
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
BackportStatusService
|
||||||
|
|
||||||
|
EvalPatchedStatusAsync()
|
||||||
|
**Tier 1**: FetchRulesWithDerivativeMapping() [NEW]
|
||||||
|
Query RHEL try Alma/Rocky if not found
|
||||||
|
**Tier 2-4**: GetRulesAsync() (existing)
|
||||||
|
**Tier 5**: EvaluateRangeRules() [FIXED]
|
||||||
|
Hierarchical resolver with version comparators [NEW]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IReadOnlyDictionary<PackageEcosystem, IVersionComparator>
|
||||||
|
RPM RpmVersionComparer (epoch:version-release)
|
||||||
|
Deb DebianVersionComparer (epoch:upstream-debian~pre)
|
||||||
|
Alpine ApkVersionComparer (X.Y.Z_pN-rN)
|
||||||
|
Fallback StringVersionComparer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Rules BugCVE mapping
|
||||||
|
|
||||||
|
|
||||||
|
IFixRuleRepository IBugCveMappingService
|
||||||
|
+ DistroMappings DebianSecurityTracker
|
||||||
|
+ ChangelogParser RedHatBugzilla (stub)
|
||||||
|
(with Bug IDs) UbuntuCVETracker
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Component Design
|
||||||
|
|
||||||
|
### 2.1 BackportStatusService (Enhanced)
|
||||||
|
|
||||||
|
**Responsibilities:**
|
||||||
|
- Orchestrate 5-tier evidence hierarchy
|
||||||
|
- Inject and delegate to version comparators
|
||||||
|
- Apply derivative distro mapping logic
|
||||||
|
- Aggregate evidence from multiple tiers
|
||||||
|
- Return confident verdicts with audit trails
|
||||||
|
|
||||||
|
**Key Methods:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public sealed class BackportStatusService
|
||||||
|
{
|
||||||
|
private readonly IFixRuleRepository _ruleRepository;
|
||||||
|
private readonly IReadOnlyDictionary<PackageEcosystem, IVersionComparator> _comparators;
|
||||||
|
private readonly IBugCveMappingService? _bugMapper; // Optional
|
||||||
|
|
||||||
|
// TIER 1: Try derivative OVAL/CSAF
|
||||||
|
private async ValueTask<IReadOnlyList<IFixRule>> FetchRulesWithDerivativeMapping(
|
||||||
|
BackportContext context,
|
||||||
|
PackageInstance package,
|
||||||
|
CveId cve,
|
||||||
|
CancellationToken ct);
|
||||||
|
|
||||||
|
// TIER 2-4: Existing rule sources (unchanged)
|
||||||
|
// TIER 5: Evaluate NVD ranges with version comparators
|
||||||
|
private BackportVerdict EvaluateRangeRules(
|
||||||
|
CveId cve,
|
||||||
|
PackageInstance package,
|
||||||
|
IReadOnlyList<RangeRule> rules);
|
||||||
|
|
||||||
|
// Helper: Get comparator for ecosystem
|
||||||
|
private IVersionComparator GetComparatorForEcosystem(PackageEcosystem ecosystem) =>
|
||||||
|
_comparators.GetValueOrDefault(ecosystem, StringVersionComparer.Instance);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependency Injection:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
builder.Services.AddSingleton<IBackportStatusService, BackportStatusService>();
|
||||||
|
builder.Services.AddSingleton<IRpmVersionComparer, RpmVersionComparer>();
|
||||||
|
builder.Services.AddSingleton<IDebianVersionComparer, DebianVersionComparer>();
|
||||||
|
builder.Services.AddSingleton<IApkVersionComparer, ApkVersionComparer>();
|
||||||
|
builder.Services.AddSingleton<IBugCveMappingService, CompositeBugCveMappingService>();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.2 DistroMappings (New Component)
|
||||||
|
|
||||||
|
**File:** src/__Libraries/StellaOps.DistroIntel/DistroDerivative.cs
|
||||||
|
|
||||||
|
**Purpose:** Define and query derivative distro relationships (RHELAlma/Rocky, etc.)
|
||||||
|
|
||||||
|
**Data Model:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public enum DerivativeConfidence
|
||||||
|
{
|
||||||
|
High, // ABI-compatible rebuilds (Alma/Rocky RHEL)
|
||||||
|
Medium // Modified derivatives (Mint Ubuntu, Ubuntu Debian)
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed record DistroDerivative(
|
||||||
|
string CanonicalDistro, // "rhel"
|
||||||
|
string DerivativeDistro, // "almalinux"
|
||||||
|
int MajorRelease, // 9
|
||||||
|
DerivativeConfidence Confidence);
|
||||||
|
|
||||||
|
public static class DistroMappings
|
||||||
|
{
|
||||||
|
public static readonly ImmutableArray<DistroDerivative> Derivatives = [...];
|
||||||
|
|
||||||
|
public static IEnumerable<DistroDerivative> FindDerivativesFor(
|
||||||
|
string distro,
|
||||||
|
int majorRelease);
|
||||||
|
|
||||||
|
public static decimal GetConfidenceMultiplier(DerivativeConfidence conf);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage Pattern:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// When fetching rules for Rocky 9:
|
||||||
|
var derivatives = DistroMappings.FindDerivativesFor("rhel", 9);
|
||||||
|
// Returns: [("rhel", "almalinux", 9, High), ("rhel", "rocky", 9, High)]
|
||||||
|
|
||||||
|
foreach (var d in derivatives.OrderByDescending(x => x.Confidence))
|
||||||
|
{
|
||||||
|
var derivativeRules = await _repo.GetRulesAsync(ctx with { Distro = d.DerivativeDistro }, ...);
|
||||||
|
if (derivativeRules.Any())
|
||||||
|
{
|
||||||
|
// Apply 0.95 multiplier for High confidence
|
||||||
|
return derivativeRules.Select(r => r with {
|
||||||
|
Confidence = r.Confidence * 0.95m
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.3 IBugCveMappingService (New Interface)
|
||||||
|
|
||||||
|
**File:** src/__Libraries/StellaOps.BugTracking/IBugCveMappingService.cs
|
||||||
|
|
||||||
|
**Purpose:** Resolve distro bug IDs to CVE IDs
|
||||||
|
|
||||||
|
**Interface:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IBugCveMappingService
|
||||||
|
{
|
||||||
|
ValueTask<IReadOnlyList<CveId>> LookupCvesAsync(
|
||||||
|
BugId bugId,
|
||||||
|
CancellationToken ct = default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed record BugId(string Tracker, string Id);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Implementations:**
|
||||||
|
|
||||||
|
1. **DebianSecurityTrackerClient**
|
||||||
|
- Source: https://security-tracker.debian.org/tracker/data/json
|
||||||
|
- Caching: 1h TTL, in-memory
|
||||||
|
|
||||||
|
2. **RedHatBugzillaClient** (stub)
|
||||||
|
- Requires authentication cache pre-populated mappings
|
||||||
|
- Future: integrate with RHBZ API
|
||||||
|
|
||||||
|
3. **UbuntuCVETrackerClient**
|
||||||
|
- Source: https://ubuntu.com/security/cves scraper
|
||||||
|
- Caching: 1h TTL
|
||||||
|
|
||||||
|
4. **CompositeBugCveMappingService**
|
||||||
|
- Routes to correct implementation based on BugId.Tracker
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var bugId = new BugId("Debian", "987654");
|
||||||
|
var cves = await _bugMapper.LookupCvesAsync(bugId);
|
||||||
|
// Returns: [CVE-2024-1234, CVE-2024-5678]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.4 ChangelogParser (Enhanced)
|
||||||
|
|
||||||
|
**File:** src/Concelier/__Libraries/StellaOps.Concelier.SourceIntel/ChangelogParser.cs
|
||||||
|
|
||||||
|
**Changes:**
|
||||||
|
- Add regex patterns for bug IDs (Debian, RHBZ, Launchpad)
|
||||||
|
- Extend ChangelogEntry record to include BugIds collection
|
||||||
|
- Extract both CVE IDs and bug IDs in parallel
|
||||||
|
|
||||||
|
**Updated Model:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public sealed record ChangelogEntry(
|
||||||
|
string Version,
|
||||||
|
DateTimeOffset Date,
|
||||||
|
IReadOnlyList<CveId> CveIds,
|
||||||
|
IReadOnlyList<BugId> BugIds, // NEW
|
||||||
|
string Description);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Regex Patterns:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[GeneratedRegex(@"CVE-\d{4}-\d{4,}")]
|
||||||
|
private static partial Regex CvePatternRegex(); // Existing
|
||||||
|
|
||||||
|
[GeneratedRegex(@"Closes:\s*#(\d+)", RegexOptions.IgnoreCase)]
|
||||||
|
private static partial Regex DebianBugRegex(); // NEW
|
||||||
|
|
||||||
|
[GeneratedRegex(@"(?:RHBZ|rhbz)#(\d+)", RegexOptions.IgnoreCase)]
|
||||||
|
private static partial Regex RhBugzillaRegex(); // NEW
|
||||||
|
|
||||||
|
[GeneratedRegex(@"LP:\s*#(\d+)", RegexOptions.IgnoreCase)]
|
||||||
|
private static partial Regex LaunchpadBugRegex(); // NEW
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.5 HunkSigExtractor (Enhanced)
|
||||||
|
|
||||||
|
**File:** src/Feedser/StellaOps.Feedser.Core/HunkSigExtractor.cs
|
||||||
|
|
||||||
|
**Changes:**
|
||||||
|
- Extract function signatures from patch context
|
||||||
|
- Populate PatchHunkSig.AffectedFunctions (currently null)
|
||||||
|
- Support C/C++, Python, Go function patterns
|
||||||
|
|
||||||
|
**Function Extraction Logic:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private static IReadOnlyList<string> ExtractFunctionsFromContext(PatchHunk hunk)
|
||||||
|
{
|
||||||
|
var functions = new HashSet<string>();
|
||||||
|
|
||||||
|
// C/C++: "static void foo(" or "int bar("
|
||||||
|
foreach (Match m in CFunctionRegex().Matches(hunk.Context))
|
||||||
|
functions.Add(m.Groups[1].Value);
|
||||||
|
|
||||||
|
// Python: "def foo(" or "class Bar:"
|
||||||
|
foreach (Match m in PythonFunctionRegex().Matches(hunk.Context))
|
||||||
|
functions.Add(m.Groups[1].Value);
|
||||||
|
|
||||||
|
// Go: "func (r *Receiver) Method("
|
||||||
|
foreach (Match m in GoFunctionRegex().Matches(hunk.Context))
|
||||||
|
functions.Add(m.Groups[1].Value);
|
||||||
|
|
||||||
|
return functions.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage:
|
||||||
|
AffectedFunctions = ExtractFunctionsFromContext(hunk),
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Data Models
|
||||||
|
|
||||||
|
### 3.1 BackportVerdict (Existing, No Changes)
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public sealed record BackportVerdict(
|
||||||
|
FixStatus Status, // Fixed | Vulnerable | Unknown
|
||||||
|
VerdictConfidence Confidence, // High | Medium | Low
|
||||||
|
RuleType EvidenceSource, // Boundary | Range | Changelog | Patch
|
||||||
|
EvidencePointer EvidencePointer, // URI, digest, timestamp
|
||||||
|
string? ConflictReason);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 RulePriority (Updated Enum)
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public enum RulePriority
|
||||||
|
{
|
||||||
|
// Tier 1: OVAL/CSAF evidence
|
||||||
|
DistroNativeOval = 100, // Distro's own OVAL/CSAF
|
||||||
|
DerivativeOvalHigh = 95, // Alma/Rocky for RHEL
|
||||||
|
DerivativeOvalMedium = 90, // Mint for Ubuntu
|
||||||
|
|
||||||
|
// Tier 2: Changelog evidence
|
||||||
|
ChangelogExplicitCve = 85, // Direct CVE mention
|
||||||
|
ChangelogBugIdMapped = 75, // Bug ID CVE mapping
|
||||||
|
|
||||||
|
// Tier 3: Source patches
|
||||||
|
SourcePatchExactMatch = 70, // Exact hunk hash match
|
||||||
|
SourcePatchFuzzyMatch = 60, // Function name + context match
|
||||||
|
|
||||||
|
// Tier 4: Upstream commits
|
||||||
|
UpstreamCommitExactParity = 55, // 100% hunk parity
|
||||||
|
UpstreamCommitPartialMatch = 45, // Partial context match
|
||||||
|
|
||||||
|
// Tier 5: NVD range heuristic
|
||||||
|
NvdRangeHeuristic = 20 // Version range check (low confidence)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 EvidencePointer (Existing, Extended)
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public sealed record EvidencePointer(
|
||||||
|
string Type, // "OvalAdvisory" | "DebianChangelog" | "NvdCpeRange"
|
||||||
|
string Uri, // "oval:ALSA-2024-1234" | "deb:curl/changelog#L42"
|
||||||
|
string SourceDigest, // SHA-256 of artifact
|
||||||
|
DateTimeOffset FetchedAt);
|
||||||
|
```
|
||||||
|
|
||||||
|
**New URI Schemes:**
|
||||||
|
- derivative:almalinuxrhel:oval:ALSA-2024-1234 (Tier 1)
|
||||||
|
- changelog:debian:curl:1.2.3#bug:987654 (Tier 2 with bug ID)
|
||||||
|
-
|
||||||
|
vd:cve/CVE-2024-1234/cpe:2.3:a:vendor:product:* (Tier 5)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Algorithms
|
||||||
|
|
||||||
|
### 4.1 Hierarchical Evidence Resolver
|
||||||
|
|
||||||
|
```pseudo
|
||||||
|
FUNCTION ResolveFixStatus(cve, package, distro, release):
|
||||||
|
|
||||||
|
// TIER 1: Try derivative OVAL/CSAF
|
||||||
|
rules FetchNativeRules(distro, release, package, cve)
|
||||||
|
|
||||||
|
IF rules.IsEmpty THEN
|
||||||
|
derivatives DistroMappings.FindDerivativesFor(distro, release)
|
||||||
|
FOR EACH derivative IN derivatives ORDER BY Confidence DESC:
|
||||||
|
derivativeRules FetchNativeRules(
|
||||||
|
derivative.DerivativeDistro,
|
||||||
|
release,
|
||||||
|
package,
|
||||||
|
cve)
|
||||||
|
|
||||||
|
IF derivativeRules.IsNotEmpty THEN
|
||||||
|
confidenceMultiplier derivative.Confidence == High ? 0.95 : 0.80
|
||||||
|
rules ApplyConfidencePenalty(derivativeRules, confidenceMultiplier)
|
||||||
|
BREAK // Use first successful derivative
|
||||||
|
END IF
|
||||||
|
END FOR
|
||||||
|
END IF
|
||||||
|
|
||||||
|
// TIER 2-4: Existing sources (changelog, patches, commits)
|
||||||
|
IF rules.IsEmpty THEN
|
||||||
|
rules FetchEvidenceBasedRules(distro, package, cve)
|
||||||
|
END IF
|
||||||
|
|
||||||
|
// TIER 5: NVD range fallback
|
||||||
|
IF rules.IsEmpty THEN
|
||||||
|
rules FetchNvdRangeRules(cve, package)
|
||||||
|
END IF
|
||||||
|
|
||||||
|
// Evaluate rules with version comparators
|
||||||
|
RETURN EvaluateRulesWithVersionSemantics(rules, package)
|
||||||
|
END FUNCTION
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Version Comparison with Ecosystem-Specific Logic
|
||||||
|
|
||||||
|
```pseudo
|
||||||
|
FUNCTION CompareVersions(v1, v2, ecosystem):
|
||||||
|
comparator GetComparatorForEcosystem(ecosystem)
|
||||||
|
|
||||||
|
MATCH ecosystem:
|
||||||
|
CASE RPM:
|
||||||
|
// Parse epoch:version-release
|
||||||
|
// Compare epoch first, then version, then release
|
||||||
|
// Handle ~ (pre-release) and ^ (post-release)
|
||||||
|
RETURN RpmVersionComparer.CompareWithProof(v1, v2)
|
||||||
|
|
||||||
|
CASE Debian:
|
||||||
|
// Parse epoch:upstream-debian~pre
|
||||||
|
// Tilde sorting: 1.0~beta < 1.0
|
||||||
|
RETURN DebianVersionComparer.CompareWithProof(v1, v2)
|
||||||
|
|
||||||
|
CASE Alpine:
|
||||||
|
// Parse X.Y.Z_pN-rN
|
||||||
|
// _p = patch level, -r = package revision
|
||||||
|
RETURN ApkVersionComparer.CompareWithProof(v1, v2)
|
||||||
|
|
||||||
|
DEFAULT:
|
||||||
|
// Fallback to SemVer or string comparison
|
||||||
|
RETURN StringVersionComparer.Compare(v1, v2)
|
||||||
|
END MATCH
|
||||||
|
END FUNCTION
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 Range Evaluation (Tier 5)
|
||||||
|
|
||||||
|
```pseudo
|
||||||
|
FUNCTION EvaluateRangeRules(cve, package, rangeRules):
|
||||||
|
comparator GetComparatorForEcosystem(package.Ecosystem)
|
||||||
|
|
||||||
|
FOR EACH rule IN rangeRules ORDER BY Priority DESC:
|
||||||
|
range rule.AffectedRange
|
||||||
|
inRange TRUE
|
||||||
|
|
||||||
|
// Check lower bound
|
||||||
|
IF range.MinVersion IS NOT NULL THEN
|
||||||
|
cmp comparator.Compare(package.Version, range.MinVersion)
|
||||||
|
inRange inRange AND (range.MinInclusive ? cmp >= 0 : cmp > 0)
|
||||||
|
END IF
|
||||||
|
|
||||||
|
// Check upper bound
|
||||||
|
IF range.MaxVersion IS NOT NULL THEN
|
||||||
|
cmp comparator.Compare(package.Version, range.MaxVersion)
|
||||||
|
inRange inRange AND (range.MaxInclusive ? cmp <= 0 : cmp < 0)
|
||||||
|
END IF
|
||||||
|
|
||||||
|
IF inRange THEN
|
||||||
|
RETURN Verdict(Status: VULNERABLE, Confidence: LOW, Evidence: rule)
|
||||||
|
END IF
|
||||||
|
END FOR
|
||||||
|
|
||||||
|
RETURN Verdict(Status: UNKNOWN, Confidence: LOW)
|
||||||
|
END FUNCTION
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 Confidence Scoring
|
||||||
|
|
||||||
|
```pseudo
|
||||||
|
FUNCTION GetConfidenceForPriority(priority):
|
||||||
|
IF priority >= 75 THEN // Tier 1-2
|
||||||
|
RETURN VerdictConfidence.High
|
||||||
|
ELSE IF priority >= 45 THEN // Tier 3-4
|
||||||
|
RETURN VerdictConfidence.Medium
|
||||||
|
ELSE // Tier 5
|
||||||
|
RETURN VerdictConfidence.Low
|
||||||
|
END IF
|
||||||
|
END FUNCTION
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Integration Points
|
||||||
|
|
||||||
|
### 5.1 Feedser Integration (Evidence Ingestion)
|
||||||
|
|
||||||
|
**Components:**
|
||||||
|
- OvalFeedProcessor Tier 1 (OVAL advisory parsing)
|
||||||
|
- CsafFeedProcessor Tier 1 (CSAF VEX parsing)
|
||||||
|
- ChangelogFeedProcessor Tier 2 (enhanced with bug ID extraction)
|
||||||
|
- PatchFeedProcessor Tier 3 (HunkSigExtractor with functions)
|
||||||
|
|
||||||
|
**Data Flow:**
|
||||||
|
|
||||||
|
```
|
||||||
|
Feedser Ingestion Pipeline
|
||||||
|
|
||||||
|
OVAL/CSAF Normalize Store with distro tags
|
||||||
|
(almalinux, rocky, rhel)
|
||||||
|
|
||||||
|
Changelogs Parse Extract CVEs + Bug IDs
|
||||||
|
Map Bug IDs to CVEs (async)
|
||||||
|
|
||||||
|
Patches Extract hunks Compute hunk sigs + functions
|
||||||
|
Store in content-addressed storage
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 VexLens Integration (Verdict Consumption)
|
||||||
|
|
||||||
|
**Components:**
|
||||||
|
- VexConsensusEngine Aggregates verdicts from BackportStatusService
|
||||||
|
- CycloneDxVexEmitter Emits signed VEX statements with evidence
|
||||||
|
|
||||||
|
**Enhancements:**
|
||||||
|
- Include EvidencePointer URIs in VEX statements
|
||||||
|
- Add confidence field (mapped from VerdictConfidence)
|
||||||
|
- Annotate Tier 5 verdicts with justification: "range-based heuristic"
|
||||||
|
|
||||||
|
**Example VEX Output:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"vulnerability": {
|
||||||
|
"id": "CVE-2024-1234"
|
||||||
|
},
|
||||||
|
"analysis": {
|
||||||
|
"state": "resolved",
|
||||||
|
"justification": "code_not_present",
|
||||||
|
"responses": ["will_not_fix", "update"],
|
||||||
|
"detail": "Fixed in curl-7.76.1-26.el9_3.2 (backport)",
|
||||||
|
"confidence": "high",
|
||||||
|
"evidence": [
|
||||||
|
{
|
||||||
|
"type": "OvalAdvisory",
|
||||||
|
"uri": "derivative:almalinuxrocky:oval:ALSA-2024-1234",
|
||||||
|
"digest": "sha256:abc123...",
|
||||||
|
"tier": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 External API Integrations
|
||||||
|
|
||||||
|
| API | Purpose | Caching | Fallback |
|
||||||
|
|-----|---------|---------|----------|
|
||||||
|
| Debian Security Tracker | Bug ID CVE mapping | 1h TTL | Skip bug ID evidence |
|
||||||
|
| Red Hat Bugzilla | Bug ID CVE mapping | Pre-populated cache | Skip bug ID evidence |
|
||||||
|
| Ubuntu CVE Tracker | Bug ID CVE mapping | 1h TTL | Skip bug ID evidence |
|
||||||
|
|
||||||
|
**Rate Limiting:**
|
||||||
|
- Debian: No explicit limit, but batch requests every 5 minutes
|
||||||
|
- RHBZ: Requires auth, use cached dump
|
||||||
|
- Ubuntu: Scraper-based, respect robots.txt (1 req/sec)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Security & Compliance
|
||||||
|
|
||||||
|
### 6.1 Evidence Integrity
|
||||||
|
|
||||||
|
**Requirements:**
|
||||||
|
- All evidence artifacts must be cryptographically hashed (SHA-256)
|
||||||
|
- Store SourceDigest in EvidencePointer
|
||||||
|
- Enable deterministic replay by re-fetching and re-hashing
|
||||||
|
|
||||||
|
**Implementation:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public static string ComputeDigest(byte[] artifact) =>
|
||||||
|
Convert.ToHexString(SHA256.HashData(artifact)).ToLowerInvariant();
|
||||||
|
|
||||||
|
var digest = ComputeDigest(Encoding.UTF8.GetBytes(ovalXml));
|
||||||
|
var pointer = new EvidencePointer(
|
||||||
|
Type: "OvalAdvisory",
|
||||||
|
Uri: $"oval:ALSA-2024-1234",
|
||||||
|
SourceDigest: digest,
|
||||||
|
FetchedAt: DateTimeOffset.UtcNow);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 Audit Trail
|
||||||
|
|
||||||
|
**Logging Requirements:**
|
||||||
|
- Log every tier attempted (1 2 ... 5)
|
||||||
|
- Log reason for tier fallback (e.g., "Tier 1: no OVAL found for rocky 9")
|
||||||
|
- Log derivative mapping decisions (e.g., "Using AlmaLinux OVAL for Rocky 9, confidence penalty 0.05")
|
||||||
|
- Log version comparison details (e.g., "1:2.0 > 3.0 (epoch wins)")
|
||||||
|
|
||||||
|
**Structured Logging Format:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"timestamp": "2025-12-30T12:34:56Z",
|
||||||
|
"level": "INFO",
|
||||||
|
"message": "Tier 1 fallback: derivative OVAL found",
|
||||||
|
"cve": "CVE-2024-1234",
|
||||||
|
"package": "curl-7.76.1-26.el9_3.2",
|
||||||
|
"distro": "rocky 9",
|
||||||
|
"derivativeUsed": "almalinux 9",
|
||||||
|
"confidence": 0.95,
|
||||||
|
"tier": 1,
|
||||||
|
"evidenceUri": "derivative:almalinuxrocky:oval:ALSA-2024-1234"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 Signed VEX Attestations
|
||||||
|
|
||||||
|
**Signature Method:** in-toto/DSSE with Ed25519 keys
|
||||||
|
|
||||||
|
**Signed Payload:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"payloadType": "application/vnd.cyclonedx+json",
|
||||||
|
"payload": "<base64-encoded CycloneDX VEX>",
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"keyid": "SHA256:abc123...",
|
||||||
|
"sig": "<base64-encoded signature>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Replay Provenance:**
|
||||||
|
- Include feed snapshot digest
|
||||||
|
- Include resolver policy version
|
||||||
|
- Store signed attestation in content-addressed storage
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Performance Considerations
|
||||||
|
|
||||||
|
### 7.1 Latency Targets
|
||||||
|
|
||||||
|
| Tier | Operation | Target Latency | Notes |
|
||||||
|
|------|-----------|----------------|-------|
|
||||||
|
| 1 | Derivative OVAL query | <50ms | In-memory or local DB |
|
||||||
|
| 2 | Changelog parsing | <100ms | Pre-indexed by package version |
|
||||||
|
| 3 | Patch hunk matching | <150ms | Content-addressed lookup |
|
||||||
|
| 4 | Upstream commit mapping | <500ms | May require git fetch (cached) |
|
||||||
|
| 5 | NVD range check | <50ms | Simple version comparison |
|
||||||
|
|
||||||
|
**Overall P95 Latency Goal:** <200ms for typical case (Tier 1-3)
|
||||||
|
|
||||||
|
### 7.2 Caching Strategy
|
||||||
|
|
||||||
|
**In-Memory Caches:**
|
||||||
|
- Bug ID CVE mappings: 1h TTL, max 10,000 entries
|
||||||
|
- Derivative OVAL queries: 5min TTL, max 5,000 entries
|
||||||
|
- Version comparison results: 10min TTL, max 50,000 entries
|
||||||
|
|
||||||
|
**Persistent Caches:**
|
||||||
|
- OVAL/CSAF feeds: File-based, refresh every 6h
|
||||||
|
- Patch hunk signatures: Content-addressed storage (immutable)
|
||||||
|
|
||||||
|
### 7.3 Scalability
|
||||||
|
|
||||||
|
**Concurrency:**
|
||||||
|
- Parallel tier evaluation within single CVE (Tier 1-3 can run concurrently if needed)
|
||||||
|
- Bulk CVE scans: Process 100 CVEs in parallel with semaphore limit
|
||||||
|
|
||||||
|
**Database Optimization:**
|
||||||
|
- Index on (distro, release, package_name, cve_id)
|
||||||
|
- Partition OVAL/CSAF rules by distro family (rhel, debian, alpine)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**End of Design Document**
|
||||||
1039
docs/implplan/SPRINT_20251230_001_BE_backport_resolver_TESTS.md
Normal file
1039
docs/implplan/SPRINT_20251230_001_BE_backport_resolver_TESTS.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,906 @@
|
|||||||
|
# SPRINT_20251230_001_BE_backport_resolver_tiered_evidence
|
||||||
|
|
||||||
|
## Sprint Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| **Sprint ID** | SPRINT_20251230_001_BE |
|
||||||
|
| **Topic** | Tiered Evidence Backport Resolver Enhancement |
|
||||||
|
| **Module** | Concelier.BackportProof, Concelier.SourceIntel, Feedser.Core |
|
||||||
|
| **Working Directory** | `src/Concelier/__Libraries/StellaOps.Concelier.BackportProof/` |
|
||||||
|
| **Priority** | P0 - Critical |
|
||||||
|
| **Estimated Effort** | 5 days |
|
||||||
|
| **Dependencies** | StellaOps.VersionComparison, StellaOps.Concelier.Merge |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Executive Summary
|
||||||
|
|
||||||
|
This sprint addresses critical gaps in the backport patch resolver that cause false positives/negatives when determining if a CVE is fixed in Linux distribution packages. The current implementation uses string comparison for version matching and lacks derivative distro mapping, resulting in incorrect vulnerability assessments.
|
||||||
|
|
||||||
|
### Key Deliverables
|
||||||
|
|
||||||
|
1. Wire ecosystem-specific version comparators into BackportStatusService
|
||||||
|
2. Implement RangeRule evaluation for NVD fallback (Tier 5)
|
||||||
|
3. Add derivative distro mapping for OVAL/CSAF cross-referencing (Tier 1)
|
||||||
|
4. Enhance changelog parsing with bug ID → CVE mapping (Tier 2)
|
||||||
|
5. Extract affected functions from patch context (Tier 3/4)
|
||||||
|
6. Align confidence scoring to five-tier evidence hierarchy
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Background & Problem Statement
|
||||||
|
|
||||||
|
### Current State
|
||||||
|
|
||||||
|
The `BackportStatusService` uses `string.Compare()` for version comparison:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// BackportStatusService.cs:198
|
||||||
|
var isPatched = string.Compare(package.InstalledVersion, fixedVersion, StringComparison.Ordinal) >= 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Failures:**
|
||||||
|
- `1.2.10` vs `1.2.9` → returns `-1` (should be `+1`)
|
||||||
|
- `1:2.0` vs `3.0` (epoch) → completely wrong
|
||||||
|
- `1.2.3~beta` vs `1.2.3` (tilde) → wrong order
|
||||||
|
|
||||||
|
### Proposed Five-Tier Evidence Hierarchy
|
||||||
|
|
||||||
|
| Tier | Evidence Source | Confidence | Priority |
|
||||||
|
|------|-----------------|------------|----------|
|
||||||
|
| 1 | Derivative OVAL/CSAF (same release) | 0.95-0.98 | 100 |
|
||||||
|
| 2 | Changelog CVE markers | 0.75-0.85 | 85 |
|
||||||
|
| 3 | Source patch files (HunkSig) | 0.80-0.95 | 70 |
|
||||||
|
| 4 | Upstream commit mapping | 0.55-0.85 | 55 |
|
||||||
|
| 5 | NVD version ranges (fallback) | Low only | 20 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Delivery Tracker
|
||||||
|
|
||||||
|
### Phase 1: Version Comparator Integration (P0)
|
||||||
|
|
||||||
|
| Task ID | Description | Status | Assignee | Notes |
|
||||||
|
|---------|-------------|--------|----------|-------|
|
||||||
|
| BP-101 | Create IVersionComparatorFactory interface | TODO | | DI registration |
|
||||||
|
| BP-102 | Wire comparators into BackportStatusService | TODO | | RPM, DEB, APK |
|
||||||
|
| BP-103 | Update EvaluateBoundaryRules with proof lines | TODO | | Audit trail |
|
||||||
|
| BP-104 | Unit tests for version comparison edge cases | TODO | | Golden datasets |
|
||||||
|
| BP-105 | Integration test: epoch handling | TODO | | `1:2.0` vs `3.0` |
|
||||||
|
|
||||||
|
### Phase 2: RangeRule Implementation (P0)
|
||||||
|
|
||||||
|
| Task ID | Description | Status | Assignee | Notes |
|
||||||
|
|---------|-------------|--------|----------|-------|
|
||||||
|
| BP-201 | Implement EvaluateRangeRules with comparators | TODO | | Min/max bounds |
|
||||||
|
| BP-202 | Handle inclusive/exclusive boundaries | TODO | | `[` vs `(` |
|
||||||
|
| BP-203 | Add Low confidence for NVD-sourced ranges | TODO | | Tier 5 |
|
||||||
|
| BP-204 | Unit tests for range edge cases | TODO | | Open/closed |
|
||||||
|
| BP-205 | Integration test: NVD fallback path | TODO | | E2E flow |
|
||||||
|
|
||||||
|
### Phase 3: Derivative Distro Mapping (P1)
|
||||||
|
|
||||||
|
| Task ID | Description | Status | Assignee | Notes |
|
||||||
|
|---------|-------------|--------|----------|-------|
|
||||||
|
| BP-301 | Create DistroDerivativeMapping model | TODO | | Canonical/derivative |
|
||||||
|
| BP-302 | Add RHEL ↔ Alma/Rocky/CentOS mappings | TODO | | Major release |
|
||||||
|
| BP-303 | Add Ubuntu ↔ LinuxMint mappings | TODO | | |
|
||||||
|
| BP-304 | Add Debian ↔ Ubuntu mappings | TODO | | |
|
||||||
|
| BP-305 | Integrate into rule fetching with confidence penalty | TODO | | 0.95x multiplier |
|
||||||
|
| BP-306 | Unit tests for derivative lookup | TODO | | |
|
||||||
|
| BP-307 | Integration test: cross-distro OVAL | TODO | | RHEL→Rocky |
|
||||||
|
|
||||||
|
### Phase 4: Bug ID → CVE Mapping (P1)
|
||||||
|
|
||||||
|
| Task ID | Description | Status | Assignee | Notes |
|
||||||
|
|---------|-------------|--------|----------|-------|
|
||||||
|
| BP-401 | Add Debian bug regex extraction | TODO | | `Closes: #123` |
|
||||||
|
| BP-402 | Add RHBZ bug regex extraction | TODO | | `RHBZ#123` |
|
||||||
|
| BP-403 | Add Launchpad bug regex extraction | TODO | | `LP: #123` |
|
||||||
|
| BP-404 | Create IBugCveMappingService interface | TODO | | Async lookup |
|
||||||
|
| BP-405 | Implement DebianSecurityTrackerClient | TODO | | API client |
|
||||||
|
| BP-406 | Implement RedHatErrataClient | TODO | | API client |
|
||||||
|
| BP-407 | Cache layer for bug→CVE mappings | TODO | | 24h TTL |
|
||||||
|
| BP-408 | Unit tests for bug ID extraction | TODO | | Regex patterns |
|
||||||
|
| BP-409 | Integration test: Debian tracker lookup | TODO | | Live API |
|
||||||
|
|
||||||
|
### Phase 5: Affected Functions Extraction (P2)
|
||||||
|
|
||||||
|
| Task ID | Description | Status | Assignee | Notes |
|
||||||
|
|---------|-------------|--------|----------|-------|
|
||||||
|
| BP-501 | Create function signature regex patterns | TODO | | C, Go, Python |
|
||||||
|
| BP-502 | Implement ExtractFunctionsFromContext | TODO | | In HunkSigExtractor |
|
||||||
|
| BP-503 | Add C/C++ function pattern | TODO | | `void foo(` |
|
||||||
|
| BP-504 | Add Go function pattern | TODO | | `func (r *R) M(` |
|
||||||
|
| BP-505 | Add Python function pattern | TODO | | `def foo(` |
|
||||||
|
| BP-506 | Add Rust function pattern | TODO | | `fn foo(` |
|
||||||
|
| BP-507 | Unit tests for function extraction | TODO | | Multi-language |
|
||||||
|
| BP-508 | Enable fuzzy function matching in Tier 3/4 | TODO | | Similarity score |
|
||||||
|
|
||||||
|
### Phase 6: Confidence Tier Alignment (P2)
|
||||||
|
|
||||||
|
| Task ID | Description | Status | Assignee | Notes |
|
||||||
|
|---------|-------------|--------|----------|-------|
|
||||||
|
| BP-601 | Expand RulePriority enum | TODO | | 9 levels |
|
||||||
|
| BP-602 | Update BackportStatusService priority logic | TODO | | Tier ordering |
|
||||||
|
| BP-603 | Add confidence multipliers per tier | TODO | | |
|
||||||
|
| BP-604 | Update EvidencePointer with TierSource | TODO | | Audit |
|
||||||
|
| BP-605 | Unit tests for tier precedence | TODO | | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Decisions & Risks
|
||||||
|
|
||||||
|
### Decisions Made
|
||||||
|
|
||||||
|
| ID | Decision | Rationale | Date |
|
||||||
|
|----|----------|-----------|------|
|
||||||
|
| D-001 | Use existing VersionComparison library | Already implements rpmvercmp, dpkg, apk semantics | 2025-12-30 |
|
||||||
|
| D-002 | Derivative confidence penalty 0.95x (High) / 0.80x (Medium) | Same ABI rebuilds vs partial compatibility | 2025-12-30 |
|
||||||
|
| D-003 | Bug→CVE cache TTL 24 hours | Balance freshness vs API rate limits | 2025-12-30 |
|
||||||
|
|
||||||
|
### Open Risks
|
||||||
|
|
||||||
|
| ID | Risk | Mitigation | Status |
|
||||||
|
|----|------|------------|--------|
|
||||||
|
| R-001 | Debian Security Tracker API rate limits | Implement exponential backoff + cache | OPEN |
|
||||||
|
| R-002 | Function extraction may produce false positives | Add confidence penalty for fuzzy matches | OPEN |
|
||||||
|
| R-003 | Derivative mappings may drift across major releases | Version-specific mapping table | OPEN |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
### P0 Tasks (Must complete)
|
||||||
|
|
||||||
|
- [ ] `BackportStatusService` uses proper version comparators for all ecosystems
|
||||||
|
- [ ] `RangeRule` evaluation returns correct verdicts with Low confidence
|
||||||
|
- [ ] All existing tests pass
|
||||||
|
- [ ] New golden tests for version edge cases
|
||||||
|
|
||||||
|
### P1 Tasks (Should complete)
|
||||||
|
|
||||||
|
- [ ] Derivative distro mapping works for RHEL family
|
||||||
|
- [ ] Bug ID extraction finds Debian/RHBZ/LP references
|
||||||
|
- [ ] Bug→CVE mapping lookup is cached
|
||||||
|
|
||||||
|
### P2 Tasks (Nice to have)
|
||||||
|
|
||||||
|
- [ ] Function extraction works for C, Go, Python, Rust
|
||||||
|
- [ ] Confidence tiers aligned to five-tier hierarchy
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Test Strategy
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
|
||||||
|
| Area | Test File | Coverage Target |
|
||||||
|
|------|-----------|-----------------|
|
||||||
|
| Version comparison | `BackportStatusServiceVersionTests.cs` | All ecosystems |
|
||||||
|
| Range evaluation | `BackportStatusServiceRangeTests.cs` | Boundary conditions |
|
||||||
|
| Derivative mapping | `DistroDerivativeMappingTests.cs` | All supported distros |
|
||||||
|
| Bug ID extraction | `ChangelogBugIdExtractionTests.cs` | Regex patterns |
|
||||||
|
| Function extraction | `HunkSigFunctionExtractionTests.cs` | Multi-language |
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
|
||||||
|
| Scenario | Test File | External Dependencies |
|
||||||
|
|----------|-----------|----------------------|
|
||||||
|
| Cross-distro OVAL | `CrossDistroOvalIntegrationTests.cs` | None (fixtures) |
|
||||||
|
| Bug→CVE lookup | `BugCveMappingIntegrationTests.cs` | Debian Tracker API |
|
||||||
|
| Full resolver flow | `BackportResolverE2ETests.cs` | PostgreSQL (Testcontainers) |
|
||||||
|
|
||||||
|
### Golden Datasets
|
||||||
|
|
||||||
|
Location: `src/__Tests/__Datasets/backport-resolver/`
|
||||||
|
|
||||||
|
| Dataset | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `rpm-version-edge-cases.json` | Epoch, tilde, release variations |
|
||||||
|
| `deb-version-edge-cases.json` | Epoch, revision, ubuntu suffixes |
|
||||||
|
| `apk-version-edge-cases.json` | Pre-release suffixes, pkgrel |
|
||||||
|
| `cross-distro-oval-fixtures/` | RHEL/Rocky/Alma advisory samples |
|
||||||
|
| `changelog-with-bugids/` | Debian/RPM changelogs with bug refs |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Execution Log
|
||||||
|
|
||||||
|
| Date | Event | Details |
|
||||||
|
|------|-------|---------|
|
||||||
|
| 2025-12-30 | Sprint created | Initial planning and gap analysis |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- `src/Concelier/__Libraries/StellaOps.Concelier.BackportProof/Services/BackportStatusService.cs`
|
||||||
|
- `src/Concelier/__Libraries/StellaOps.Concelier.BackportProof/Models/FixRuleModels.cs`
|
||||||
|
- `src/Concelier/__Libraries/StellaOps.Concelier.Merge/Comparers/RpmVersionComparer.cs`
|
||||||
|
- `src/Concelier/__Libraries/StellaOps.Concelier.Merge/Comparers/ApkVersionComparer.cs`
|
||||||
|
- `src/Concelier/__Libraries/StellaOps.Concelier.SourceIntel/ChangelogParser.cs`
|
||||||
|
- `src/Feedser/StellaOps.Feedser.Core/HunkSigExtractor.cs`
|
||||||
|
- `src/VexLens/StellaOps.VexLens/Consensus/VexConsensusEngine.cs`
|
||||||
|
**Key Improvements:**
|
||||||
|
- Wire existing version comparators (RpmVersionComparer, ApkVersionComparer, DebianVersionComparer) into BackportStatusService
|
||||||
|
- Implement NVD range evaluation (Tier 5 fallback)
|
||||||
|
- Add derivative distro mapping (RHELAlma/Rocky, UbuntuMint) for Tier 1 evidence
|
||||||
|
- Extend changelog parser to extract bug IDs and map to CVEs
|
||||||
|
- Extract function signatures from patch hunks for better matching
|
||||||
|
- Align confidence scoring with 5-tier evidence hierarchy
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- Eliminates false positives from incorrect version comparisons (e.g., "1.2.10" < "1.2.9")
|
||||||
|
- Enables cross-distro evidence sharing (e.g., use AlmaLinux OVAL for RHEL)
|
||||||
|
- Provides auditable, signed VEX statements with evidence trails
|
||||||
|
- Reduces manual verification workload by 60-80%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Problem Statement
|
||||||
|
|
||||||
|
### Current Implementation Gaps
|
||||||
|
|
||||||
|
| Gap ID | Description | Severity | Current Behavior | Desired Behavior |
|
||||||
|
|--------|-------------|----------|------------------|------------------|
|
||||||
|
| GAP-001 | String-based version comparison | **CRITICAL** | "1.2.10" < "1.2.9" returns true | Use ecosystem-specific comparers (EVR, dpkg, apk) |
|
||||||
|
| GAP-002 | RangeRule returns Unknown | **CRITICAL** | NVD ranges ignored, always Unknown | Evaluate ranges with proper version semantics |
|
||||||
|
| GAP-003 | No derivative distro mapping | **HIGH** | AlmaLinux OVAL unused for RHEL scans | Map RHELAlma/Rocky, UbuntuMint with confidence |
|
||||||
|
| GAP-004 | Bug IDCVE mapping missing | **HIGH** | Only direct CVE mentions detected | Extract Debian/RHBZ/LP bug IDs, map to CVEs |
|
||||||
|
| GAP-005 | AffectedFunctions not extracted | **MEDIUM** | Hunk matching relies only on content hash | Extract C/Python/Go function signatures for fuzzy match |
|
||||||
|
| GAP-006 | Confidence tiers misaligned | **MEDIUM** | Priority values don't match evidence quality | Align with 5-tier hierarchy (Tier 1=High, Tier 5=Low) |
|
||||||
|
|
||||||
|
### Real-World Example
|
||||||
|
|
||||||
|
**Scenario:** CVE-2024-1234 in curl on Rocky Linux 9
|
||||||
|
|
||||||
|
**Current behavior:**
|
||||||
|
```
|
||||||
|
- Installed: curl-7.76.1-26.el9_3.2
|
||||||
|
- NVD says: "Fixed in 7.77.0"
|
||||||
|
- String comparison: "7.76.1-26.el9_3.2" < "7.77.0" **VULNERABLE** (WRONG!)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Root cause:** Red Hat backported the fix to 7.76.1-26, but string comparison doesn't understand epoch-version-release semantics.
|
||||||
|
|
||||||
|
**Correct behavior (after sprint):**
|
||||||
|
```
|
||||||
|
1. Check AlmaLinux OVAL (Tier 1): Found fix in curl-7.76.1-26.el9_3.2
|
||||||
|
2. Map AlmaRocky (High confidence, same ABI)
|
||||||
|
3. Verdict: **FIXED** , Confidence: High, Evidence: [Alma OVAL advisory ALSA-2024-1234]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5-Tier Evidence Hierarchy (Target Architecture)
|
||||||
|
|
||||||
|
`mermaid
|
||||||
|
graph TD
|
||||||
|
A[CVE + Package + Distro] --> B{Tier 1: Derivative OVAL/CSAF}
|
||||||
|
B -->|Found| C[Verdict: FIXED/VULNERABLE<br/>Confidence: High 0.95-0.98]
|
||||||
|
B -->|Not Found| D{Tier 2: Changelog Markers}
|
||||||
|
D -->|CVE Match| E[Verdict: FIXED<br/>Confidence: High 0.85]
|
||||||
|
D -->|Bug ID Match| F[Verdict: FIXED<br/>Confidence: Medium 0.75]
|
||||||
|
D -->|Not Found| G{Tier 3: Source Patch Files}
|
||||||
|
G -->|Exact Hunk Hash| H[Verdict: FIXED<br/>Confidence: Medium-High 0.90]
|
||||||
|
G -->|Fuzzy Function Match| I[Verdict: FIXED<br/>Confidence: Medium 0.70]
|
||||||
|
G -->|Not Found| J{Tier 4: Upstream Commit Mapping}
|
||||||
|
J -->|100% Hunk Parity| K[Verdict: FIXED<br/>Confidence: Medium 0.80]
|
||||||
|
J -->|Partial Match| L[Verdict: FIXED<br/>Confidence: Medium-Low 0.60]
|
||||||
|
J -->|Not Found| M{Tier 5: NVD Range Fallback}
|
||||||
|
M -->|In Range| N[Verdict: VULNERABLE<br/>Confidence: Low 0.40]
|
||||||
|
M -->|Out of Range| O[Verdict: FIXED<br/>Confidence: Low 0.50]
|
||||||
|
M -->|No Data| P[Verdict: UNKNOWN<br/>Confidence: Low 0.30]
|
||||||
|
`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sprint Tasks
|
||||||
|
|
||||||
|
### Phase 1: Foundation (P0 - Critical Path)
|
||||||
|
|
||||||
|
#### Task 1.1: Wire Version Comparators into BackportStatusService
|
||||||
|
- **File:** src/Concelier/__Libraries/StellaOps.Concelier.BackportProof/Services/BackportStatusService.cs
|
||||||
|
- **Effort:** 2h
|
||||||
|
- **Dependencies:** StellaOps.Concelier.Merge.Comparers
|
||||||
|
- **Acceptance Criteria:**
|
||||||
|
- [ ] Add IReadOnlyDictionary<PackageEcosystem, IVersionComparator> field
|
||||||
|
- [ ] Inject comparators in constructor (RPM, Debian, Alpine, Conda)
|
||||||
|
- [ ] Replace string.Compare() in EvaluateBoundaryRules() with comparator.CompareWithProof()
|
||||||
|
- [ ] Add fallback StringVersionComparer for unknown ecosystems
|
||||||
|
- [ ] Unit test: "1.2.10" > "1.2.9" for RPM/Deb/Alpine
|
||||||
|
- [ ] Unit test: Epoch handling "1:2.0" > "3.0"
|
||||||
|
- [ ] Unit test: Tilde pre-releases "1.2.3~beta" < "1.2.3"
|
||||||
|
|
||||||
|
**Code Snippet:**
|
||||||
|
```csharp
|
||||||
|
// BackportStatusService.cs
|
||||||
|
private readonly IReadOnlyDictionary<PackageEcosystem, IVersionComparator> _comparators;
|
||||||
|
|
||||||
|
public BackportStatusService(
|
||||||
|
IFixRuleRepository ruleRepository,
|
||||||
|
IRpmVersionComparer rpmComparer,
|
||||||
|
IDebianVersionComparer debComparer,
|
||||||
|
IApkVersionComparer apkComparer)
|
||||||
|
{
|
||||||
|
_comparators = new Dictionary<PackageEcosystem, IVersionComparator>
|
||||||
|
{
|
||||||
|
[PackageEcosystem.Rpm] = rpmComparer,
|
||||||
|
[PackageEcosystem.Deb] = debComparer,
|
||||||
|
[PackageEcosystem.Alpine] = apkComparer,
|
||||||
|
}.ToFrozenDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BackportVerdict EvaluateBoundaryRules(...)
|
||||||
|
{
|
||||||
|
var comparator = _comparators.GetValueOrDefault(
|
||||||
|
package.Key.Ecosystem,
|
||||||
|
StringVersionComparer.Instance);
|
||||||
|
|
||||||
|
var result = comparator.CompareWithProof(
|
||||||
|
package.InstalledVersion,
|
||||||
|
fixedVersion);
|
||||||
|
|
||||||
|
var isPatched = result.Result >= 0;
|
||||||
|
// ... rest of logic
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Task 1.2: Implement RangeRule Evaluation (Tier 5)
|
||||||
|
- **File:** BackportStatusService.cs::EvaluateRangeRules()
|
||||||
|
- **Effort:** 3h
|
||||||
|
- **Acceptance Criteria:**
|
||||||
|
- [ ] Evaluate AffectedRange.MinVersion and MaxVersion with inclusive/exclusive bounds
|
||||||
|
- [ ] Return FixStatus.Vulnerable if in range, FixStatus.Fixed if out of range
|
||||||
|
- [ ] Set VerdictConfidence.Low for all Tier 5 decisions
|
||||||
|
- [ ] Add evidence pointer to NVD CPE/range definition
|
||||||
|
- [ ] Handle null min/max (unbounded ranges)
|
||||||
|
- [ ] Unit test: CVE-2024-1234 with range [1.0.0, 2.0.0) versions 1.5.0 (vuln), 2.0.1 (fixed)
|
||||||
|
|
||||||
|
**Code Snippet:**
|
||||||
|
```csharp
|
||||||
|
private BackportVerdict EvaluateRangeRules(
|
||||||
|
CveId cve,
|
||||||
|
PackageInstance package,
|
||||||
|
IReadOnlyList<RangeRule> rules)
|
||||||
|
{
|
||||||
|
var comparator = _comparators.GetValueOrDefault(
|
||||||
|
package.Key.Ecosystem,
|
||||||
|
StringVersionComparer.Instance);
|
||||||
|
|
||||||
|
foreach (var rule in rules.OrderByDescending(r => r.Priority))
|
||||||
|
{
|
||||||
|
var range = rule.AffectedRange;
|
||||||
|
var inRange = true;
|
||||||
|
|
||||||
|
if (range.MinVersion != null)
|
||||||
|
{
|
||||||
|
var cmp = comparator.Compare(package.InstalledVersion, range.MinVersion);
|
||||||
|
inRange &= range.MinInclusive ? cmp >= 0 : cmp > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range.MaxVersion != null)
|
||||||
|
{
|
||||||
|
var cmp = comparator.Compare(package.InstalledVersion, range.MaxVersion);
|
||||||
|
inRange &= range.MaxInclusive ? cmp <= 0 : cmp < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inRange)
|
||||||
|
{
|
||||||
|
return new BackportVerdict(
|
||||||
|
Status: FixStatus.Vulnerable,
|
||||||
|
Confidence: VerdictConfidence.Low, // Tier 5 always Low
|
||||||
|
EvidenceSource: RuleType.Range,
|
||||||
|
EvidencePointer: new EvidencePointer(
|
||||||
|
Type: "NvdCpeRange",
|
||||||
|
Uri: $"nvd:cve/{cve}/cpe/{rule.CpeId}",
|
||||||
|
SourceDigest: ComputeDigest(rule)),
|
||||||
|
ConflictReason: null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BackportVerdict(
|
||||||
|
Status: FixStatus.Unknown,
|
||||||
|
Confidence: VerdictConfidence.Low,
|
||||||
|
ConflictReason: "No matching range rule");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 2: Derivative Distro Mapping (P1)
|
||||||
|
|
||||||
|
#### Task 2.1: Create DistroDerivative Model and Mappings
|
||||||
|
- **New File:** src/__Libraries/StellaOps.DistroIntel/DistroDerivative.cs
|
||||||
|
- **Effort:** 2h
|
||||||
|
- **Acceptance Criteria:**
|
||||||
|
- [ ] Define DistroDerivative record with canonical/derivative names, release, confidence
|
||||||
|
- [ ] Create static DistroMappings class with predefined derivatives
|
||||||
|
- [ ] Support RHELAlma/Rocky (High confidence), UbuntuMint (Medium), DebianUbuntu (Medium)
|
||||||
|
- [ ] Add FindDerivativesFor(distro, release) query method
|
||||||
|
- [ ] Unit test: Query "rhel 9" returns ["almalinux 9", "rocky 9"]
|
||||||
|
|
||||||
|
**Code Snippet:**
|
||||||
|
```csharp
|
||||||
|
namespace StellaOps.DistroIntel;
|
||||||
|
|
||||||
|
public enum DerivativeConfidence
|
||||||
|
{
|
||||||
|
High, // Same ABI, byte-for-byte rebuilds (Alma/Rocky from RHEL)
|
||||||
|
Medium // Derivative with modifications (Ubuntu from Debian, Mint from Ubuntu)
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed record DistroDerivative(
|
||||||
|
string CanonicalDistro,
|
||||||
|
string DerivativeDistro,
|
||||||
|
int MajorRelease,
|
||||||
|
DerivativeConfidence Confidence);
|
||||||
|
|
||||||
|
public static class DistroMappings
|
||||||
|
{
|
||||||
|
public static readonly ImmutableArray<DistroDerivative> Derivatives =
|
||||||
|
[
|
||||||
|
new("rhel", "almalinux", 9, DerivativeConfidence.High),
|
||||||
|
new("rhel", "rocky", 9, DerivativeConfidence.High),
|
||||||
|
new("rhel", "centos", 9, DerivativeConfidence.High),
|
||||||
|
new("rhel", "almalinux", 8, DerivativeConfidence.High),
|
||||||
|
new("rhel", "rocky", 8, DerivativeConfidence.High),
|
||||||
|
new("ubuntu", "linuxmint", 22, DerivativeConfidence.Medium),
|
||||||
|
new("ubuntu", "linuxmint", 20, DerivativeConfidence.Medium),
|
||||||
|
new("debian", "ubuntu", 12, DerivativeConfidence.Medium),
|
||||||
|
];
|
||||||
|
|
||||||
|
public static IEnumerable<DistroDerivative> FindDerivativesFor(
|
||||||
|
string distro,
|
||||||
|
int majorRelease)
|
||||||
|
{
|
||||||
|
return Derivatives.Where(d =>
|
||||||
|
d.CanonicalDistro.Equals(distro, StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
d.MajorRelease == majorRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal GetConfidenceMultiplier(DerivativeConfidence conf) =>
|
||||||
|
conf switch
|
||||||
|
{
|
||||||
|
DerivativeConfidence.High => 0.95m,
|
||||||
|
DerivativeConfidence.Medium => 0.80m,
|
||||||
|
_ => 0.70m
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Task 2.2: Integrate Derivative Mapping into BackportStatusService
|
||||||
|
- **File:** BackportStatusService.cs
|
||||||
|
- **Effort:** 2h
|
||||||
|
- **Acceptance Criteria:**
|
||||||
|
- [ ] After fetching rules for target distro, if empty, try derivative mappings
|
||||||
|
- [ ] Query derivative rules and apply confidence penalty
|
||||||
|
- [ ] Annotate evidence with derivative source
|
||||||
|
- [ ] Integration test: Scan Rocky 9 with only AlmaLinux OVAL data success
|
||||||
|
|
||||||
|
**Code Snippet:**
|
||||||
|
```csharp
|
||||||
|
private async ValueTask<IReadOnlyList<IFixRule>> FetchRulesWithDerivativeMapping(
|
||||||
|
BackportContext context,
|
||||||
|
PackageInstance package,
|
||||||
|
CveId cve)
|
||||||
|
{
|
||||||
|
// Try direct distro first
|
||||||
|
var rules = await _ruleRepository.GetRulesAsync(context, package, cve);
|
||||||
|
|
||||||
|
if (rules.Count == 0)
|
||||||
|
{
|
||||||
|
var derivatives = DistroMappings.FindDerivativesFor(
|
||||||
|
context.Distro,
|
||||||
|
context.Release);
|
||||||
|
|
||||||
|
foreach (var derivative in derivatives.OrderByDescending(d => d.Confidence))
|
||||||
|
{
|
||||||
|
var derivativeContext = context with
|
||||||
|
{
|
||||||
|
Distro = derivative.DerivativeDistro
|
||||||
|
};
|
||||||
|
|
||||||
|
var derivativeRules = await _ruleRepository.GetRulesAsync(
|
||||||
|
derivativeContext,
|
||||||
|
package,
|
||||||
|
cve);
|
||||||
|
|
||||||
|
if (derivativeRules.Count > 0)
|
||||||
|
{
|
||||||
|
// Apply confidence penalty
|
||||||
|
var multiplier = DistroMappings.GetConfidenceMultiplier(
|
||||||
|
derivative.Confidence);
|
||||||
|
|
||||||
|
rules = derivativeRules.Select(r => r with
|
||||||
|
{
|
||||||
|
Confidence = r.Confidence * multiplier,
|
||||||
|
EvidencePointer = r.EvidencePointer with
|
||||||
|
{
|
||||||
|
Uri = $"derivative:{derivative.DerivativeDistro}{context.Distro}:{r.EvidencePointer.Uri}"
|
||||||
|
}
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
break; // Use first successful derivative
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 3: Bug ID CVE Mapping (P1)
|
||||||
|
|
||||||
|
#### Task 3.1: Extend ChangelogParser with Bug ID Extraction
|
||||||
|
- **File:** src/Concelier/__Libraries/StellaOps.Concelier.SourceIntel/ChangelogParser.cs
|
||||||
|
- **Effort:** 3h
|
||||||
|
- **Acceptance Criteria:**
|
||||||
|
- [ ] Add regex patterns for Debian (Closes: #123456), RHBZ (RHBZ#123456), Launchpad (LP: #123456)
|
||||||
|
- [ ] Extract bug IDs alongside CVE IDs
|
||||||
|
- [ ] Return ChangelogEntry with both CveIds and BugIds collections
|
||||||
|
- [ ] Unit test: Parse Debian changelog with "Closes: #987654" bug ID extracted
|
||||||
|
|
||||||
|
**Code Snippet:**
|
||||||
|
```csharp
|
||||||
|
[GeneratedRegex(@"Closes:\s*#(\d+)", RegexOptions.IgnoreCase)]
|
||||||
|
private static partial Regex DebianBugRegex();
|
||||||
|
|
||||||
|
[GeneratedRegex(@"(?:RHBZ|rhbz)#(\d+)", RegexOptions.IgnoreCase)]
|
||||||
|
private static partial Regex RhBugzillaRegex();
|
||||||
|
|
||||||
|
[GeneratedRegex(@"LP:\s*#(\d+)", RegexOptions.IgnoreCase)]
|
||||||
|
private static partial Regex LaunchpadBugRegex();
|
||||||
|
|
||||||
|
public sealed record ChangelogEntry(
|
||||||
|
string Version,
|
||||||
|
DateTimeOffset Date,
|
||||||
|
IReadOnlyList<CveId> CveIds,
|
||||||
|
IReadOnlyList<BugId> BugIds, // NEW
|
||||||
|
string Description);
|
||||||
|
|
||||||
|
public sealed record BugId(string Tracker, string Id)
|
||||||
|
{
|
||||||
|
public override string ToString() => $"{Tracker}#{Id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IReadOnlyList<BugId> ExtractBugIds(string line)
|
||||||
|
{
|
||||||
|
var bugs = new List<BugId>();
|
||||||
|
|
||||||
|
foreach (Match m in DebianBugRegex().Matches(line))
|
||||||
|
bugs.Add(new BugId("Debian", m.Groups[1].Value));
|
||||||
|
|
||||||
|
foreach (Match m in RhBugzillaRegex().Matches(line))
|
||||||
|
bugs.Add(new BugId("RHBZ", m.Groups[1].Value));
|
||||||
|
|
||||||
|
foreach (Match m in LaunchpadBugRegex().Matches(line))
|
||||||
|
bugs.Add(new BugId("Launchpad", m.Groups[1].Value));
|
||||||
|
|
||||||
|
return bugs;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Task 3.2: Implement BugCVE Mapping Service
|
||||||
|
- **New File:** src/__Libraries/StellaOps.BugTracking/IBugCveMappingService.cs
|
||||||
|
- **Effort:** 4h (including API clients)
|
||||||
|
- **Acceptance Criteria:**
|
||||||
|
- [ ] Define IBugCveMappingService.LookupCvesAsync(BugId)
|
||||||
|
- [ ] Implement Debian Security Tracker API client (https://security-tracker.debian.org/tracker/data/json)
|
||||||
|
- [ ] Implement Red Hat Bugzilla API stub (cache-based, due to auth complexity)
|
||||||
|
- [ ] Implement Ubuntu CVE Tracker scraper (https://ubuntu.com/security/cves)
|
||||||
|
- [ ] Cache results (1 hour TTL)
|
||||||
|
- [ ] Integration test: Debian bug #987654 CVE-2024-1234
|
||||||
|
|
||||||
|
**Stub Implementation:**
|
||||||
|
```csharp
|
||||||
|
public interface IBugCveMappingService
|
||||||
|
{
|
||||||
|
ValueTask<IReadOnlyList<CveId>> LookupCvesAsync(
|
||||||
|
BugId bugId,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class DebianSecurityTrackerClient : IBugCveMappingService
|
||||||
|
{
|
||||||
|
private readonly HttpClient _http;
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
|
||||||
|
public async ValueTask<IReadOnlyList<CveId>> LookupCvesAsync(
|
||||||
|
BugId bugId,
|
||||||
|
CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
if (bugId.Tracker != "Debian")
|
||||||
|
return [];
|
||||||
|
|
||||||
|
var cacheKey = $"debian:bug:{bugId.Id}";
|
||||||
|
if (_cache.TryGetValue(cacheKey, out IReadOnlyList<CveId>? cached))
|
||||||
|
return cached!;
|
||||||
|
|
||||||
|
var json = await _http.GetStringAsync(
|
||||||
|
"https://security-tracker.debian.org/tracker/data/json",
|
||||||
|
ct);
|
||||||
|
|
||||||
|
// Parse JSON, extract CVEs for bug ID
|
||||||
|
var cves = ParseDebianTrackerJson(json, bugId.Id);
|
||||||
|
|
||||||
|
_cache.Set(cacheKey, cves, TimeSpan.FromHours(1));
|
||||||
|
return cves;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 4: Function Extraction from Hunks (P2)
|
||||||
|
|
||||||
|
#### Task 4.1: Add Function Signature Extraction to HunkSigExtractor
|
||||||
|
- **File:** src/Feedser/StellaOps.Feedser.Core/HunkSigExtractor.cs
|
||||||
|
- **Effort:** 4h
|
||||||
|
- **Acceptance Criteria:**
|
||||||
|
- [ ] Extract C/C++ functions (static void foo(, int main()
|
||||||
|
- [ ] Extract Python functions (def foo(, class Foo:)
|
||||||
|
- [ ] Extract Go functions (unc (r *Receiver) Method()
|
||||||
|
- [ ] Populate PatchHunkSig.AffectedFunctions
|
||||||
|
- [ ] Unit test: C patch with static int ssl_verify(SSL *ssl) function extracted
|
||||||
|
|
||||||
|
**Code Snippet:**
|
||||||
|
```csharp
|
||||||
|
[GeneratedRegex(@"^\s*(?:static\s+|inline\s+)?(?:\w+\s+)+(\w+)\s*\(", RegexOptions.Multiline)]
|
||||||
|
private static partial Regex CFunctionRegex();
|
||||||
|
|
||||||
|
[GeneratedRegex(@"^\s*def\s+(\w+)\s*\(", RegexOptions.Multiline)]
|
||||||
|
private static partial Regex PythonFunctionRegex();
|
||||||
|
|
||||||
|
[GeneratedRegex(@"^\s*func\s+(?:\(\w+\s+\*?\w+\)\s+)?(\w+)\s*\(", RegexOptions.Multiline)]
|
||||||
|
private static partial Regex GoFunctionRegex();
|
||||||
|
|
||||||
|
private static IReadOnlyList<string> ExtractFunctionsFromContext(PatchHunk hunk)
|
||||||
|
{
|
||||||
|
var functions = new HashSet<string>();
|
||||||
|
var context = hunk.Context;
|
||||||
|
|
||||||
|
foreach (Match m in CFunctionRegex().Matches(context))
|
||||||
|
functions.Add(m.Groups[1].Value);
|
||||||
|
|
||||||
|
foreach (Match m in PythonFunctionRegex().Matches(context))
|
||||||
|
functions.Add(m.Groups[1].Value);
|
||||||
|
|
||||||
|
foreach (Match m in GoFunctionRegex().Matches(context))
|
||||||
|
functions.Add(m.Groups[1].Value);
|
||||||
|
|
||||||
|
return functions.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update ExtractHunkSigs:
|
||||||
|
AffectedFunctions = ExtractFunctionsFromContext(hunk),
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 5: Confidence Tier Realignment (P2)
|
||||||
|
|
||||||
|
#### Task 5.1: Update RulePriority Enum
|
||||||
|
- **File:** src/Concelier/__Libraries/StellaOps.Concelier.BackportProof/Models/FixRuleModels.cs
|
||||||
|
- **Effort:** 1h
|
||||||
|
- **Acceptance Criteria:**
|
||||||
|
- [ ] Rename/add priority values to match 5-tier hierarchy
|
||||||
|
- [ ] Ensure tier ordering: Tier 1 > Tier 2 > ... > Tier 5
|
||||||
|
- [ ] Update existing rule creation code to use new priorities
|
||||||
|
- [ ] Unit test: Verify priority ordering in resolver
|
||||||
|
|
||||||
|
**Code Snippet:**
|
||||||
|
```csharp
|
||||||
|
public enum RulePriority
|
||||||
|
{
|
||||||
|
// Tier 1: Derivative OVAL/CSAF
|
||||||
|
DistroNativeOval = 100,
|
||||||
|
DerivativeOvalHigh = 95, // Alma/Rocky for RHEL
|
||||||
|
DerivativeOvalMedium = 90, // Mint for Ubuntu
|
||||||
|
|
||||||
|
// Tier 2: Changelog markers
|
||||||
|
ChangelogExplicitCve = 85,
|
||||||
|
ChangelogBugIdMapped = 75,
|
||||||
|
|
||||||
|
// Tier 3: Source patch files
|
||||||
|
SourcePatchExactMatch = 70,
|
||||||
|
SourcePatchFuzzyMatch = 60,
|
||||||
|
|
||||||
|
// Tier 4: Upstream commit mapping
|
||||||
|
UpstreamCommitExactParity = 55,
|
||||||
|
UpstreamCommitPartialMatch = 45,
|
||||||
|
|
||||||
|
// Tier 5: NVD range fallback
|
||||||
|
NvdRangeHeuristic = 20
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Task 5.2: Map Priorities to Confidence Levels
|
||||||
|
- **File:** BackportStatusService.cs
|
||||||
|
- **Effort:** 1h
|
||||||
|
- **Acceptance Criteria:**
|
||||||
|
- [ ] Add GetConfidenceForPriority(RulePriority) helper
|
||||||
|
- [ ] Return VerdictConfidence.High for Tier 1-2, Medium for Tier 3-4, Low for Tier 5
|
||||||
|
- [ ] Use in all verdict creation paths
|
||||||
|
- [ ] Unit test: Priority 100 High, Priority 20 Low
|
||||||
|
|
||||||
|
**Code Snippet:**
|
||||||
|
```csharp
|
||||||
|
private static VerdictConfidence GetConfidenceForPriority(RulePriority priority) =>
|
||||||
|
priority switch
|
||||||
|
{
|
||||||
|
>= RulePriority.ChangelogBugIdMapped => VerdictConfidence.High,
|
||||||
|
>= RulePriority.UpstreamCommitPartialMatch => VerdictConfidence.Medium,
|
||||||
|
_ => VerdictConfidence.Low
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
### Unit Tests (Per Task)
|
||||||
|
- Task 1.1: BackportStatusServiceTests.cs::VersionComparatorIntegration
|
||||||
|
- Task 1.2: BackportStatusServiceTests.cs::RangeRuleEvaluation
|
||||||
|
- Task 2.1: DistroMappingsTests.cs
|
||||||
|
- Task 2.2: BackportStatusServiceTests.cs::DerivativeDistroMapping
|
||||||
|
- Task 3.1: ChangelogParserTests.cs::BugIdExtraction
|
||||||
|
- Task 3.2: BugCveMappingServiceTests.cs
|
||||||
|
- Task 4.1: HunkSigExtractorTests.cs::FunctionExtraction
|
||||||
|
- Task 5.1/5.2: FixRuleModelsTests.cs::ConfidenceMapping
|
||||||
|
|
||||||
|
### Integration Tests (Golden Cases)
|
||||||
|
|
||||||
|
#### Test Case 1: CVE-2024-26130 (OpenSSL on Rocky 9)
|
||||||
|
```yaml
|
||||||
|
Scenario: Backported fix with derivative OVAL
|
||||||
|
Given:
|
||||||
|
- CVE: CVE-2024-26130
|
||||||
|
- Package: openssl-3.0.7-24.el9
|
||||||
|
- Distro: rocky 9
|
||||||
|
- OVAL exists for: almalinux 9 (not rocky 9)
|
||||||
|
Expected:
|
||||||
|
- Status: FIXED
|
||||||
|
- Confidence: High (0.95)
|
||||||
|
- Evidence: AlmaLinux OVAL ALSA-2024-1234, mapped to Rocky
|
||||||
|
- Tier: 1 (Derivative OVAL)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Test Case 2: CVE-2023-12345 (curl on Debian with bug ID)
|
||||||
|
```yaml
|
||||||
|
Scenario: Changelog with Debian bug ID
|
||||||
|
Given:
|
||||||
|
- CVE: CVE-2023-12345
|
||||||
|
- Package: curl-7.88.1-10+deb12u1
|
||||||
|
- Distro: debian 12
|
||||||
|
- Changelog: "Closes: #987654" (maps to CVE-2023-12345)
|
||||||
|
Expected:
|
||||||
|
- Status: FIXED
|
||||||
|
- Confidence: Medium (0.75)
|
||||||
|
- Evidence: Debian changelog, bug #987654 CVE-2023-12345
|
||||||
|
- Tier: 2 (Changelog bug ID)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Test Case 3: CVE-2024-99999 (zlib with NVD range only)
|
||||||
|
```yaml
|
||||||
|
Scenario: Fallback to NVD range
|
||||||
|
Given:
|
||||||
|
- CVE: CVE-2024-99999
|
||||||
|
- Package: zlib-1.2.11-r3
|
||||||
|
- Distro: alpine 3.18
|
||||||
|
- No OVAL, no changelog, no patches
|
||||||
|
- NVD range: [1.2.0, 1.2.12) vulnerable
|
||||||
|
Expected:
|
||||||
|
- Status: VULNERABLE
|
||||||
|
- Confidence: Low (0.40)
|
||||||
|
- Evidence: NVD CPE range heuristic
|
||||||
|
- Tier: 5 (NVD fallback)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Tests
|
||||||
|
- Measure resolver latency: target <50ms for Tier 1-3, <500ms for Tier 4 (upstream git)
|
||||||
|
- Bulk scan: 10,000 CVEpackage combinations should complete within 5 minutes
|
||||||
|
- Cache hit rate for bugCVE mapping: target >80%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rollout Plan
|
||||||
|
|
||||||
|
### Phase 1 (Week 1): P0 Tasks
|
||||||
|
- Days 1-2: Task 1.1 (Version comparators) + Task 1.2 (Range rules)
|
||||||
|
- Day 3: Unit tests + integration testing
|
||||||
|
- Day 4: Deploy to staging, validate with golden cases
|
||||||
|
- Day 5: Production canary (10% traffic)
|
||||||
|
|
||||||
|
### Phase 2 (Week 2): P1 Tasks
|
||||||
|
- Days 1-2: Task 2.1 + 2.2 (Derivative mapping)
|
||||||
|
- Days 3-4: Task 3.1 + 3.2 (Bug ID mapping)
|
||||||
|
- Day 5: Full production rollout
|
||||||
|
|
||||||
|
### Phase 3 (Week 3): P2 Polish
|
||||||
|
- Days 1-2: Task 4.1 (Function extraction)
|
||||||
|
- Day 3: Task 5.1 + 5.2 (Confidence realignment)
|
||||||
|
- Days 4-5: Documentation + observability dashboards
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success Metrics
|
||||||
|
|
||||||
|
| Metric | Baseline (Current) | Target (Post-Sprint) | Measurement |
|
||||||
|
|--------|-------------------|----------------------|-------------|
|
||||||
|
| False positive rate | 35% | <5% | Manual audit of 500 random verdicts |
|
||||||
|
| False negative rate | 12% | <3% | Regression test suite (50 known vulns) |
|
||||||
|
| Tier 1 evidence usage | 0% | >40% | % verdicts using derivative OVAL |
|
||||||
|
| Tier 5 fallback rate | 100% | <20% | % verdicts from NVD ranges only |
|
||||||
|
| Average confidence score | 0.50 (Medium) | >0.75 (Medium-High) | Weighted average of verdicts |
|
||||||
|
| Time to verdict | 150ms | <100ms | P95 latency for single CVE evaluation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Risk Mitigation
|
||||||
|
|
||||||
|
| Risk | Likelihood | Impact | Mitigation |
|
||||||
|
|------|-----------|--------|------------|
|
||||||
|
| Version comparer regressions | Medium | High | Extensive unit tests, gradual rollout with canary |
|
||||||
|
| Derivative OVAL mismatch (NEVRA drift) | Low | Medium | Require exact NEVRA match, log mismatches |
|
||||||
|
| Bug tracker APIs rate-limit/fail | High | Medium | Aggressive caching (1h TTL), fallback to direct CVE only |
|
||||||
|
| Function extraction false positives | Medium | Low | Fuzzy matching with threshold, manual review for P2 |
|
||||||
|
| Confidence inflation | Low | High | Audit trail of all evidence, periodic manual validation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Appendix
|
||||||
|
|
||||||
|
### A. File Modification Checklist
|
||||||
|
- [ ] BackportStatusService.cs (Tasks 1.1, 1.2, 2.2, 5.2)
|
||||||
|
- [ ] FixRuleModels.cs (Task 5.1)
|
||||||
|
- [ ] ChangelogParser.cs (Task 3.1)
|
||||||
|
- [ ] HunkSigExtractor.cs (Task 4.1)
|
||||||
|
- [ ] New: DistroDerivative.cs (Task 2.1)
|
||||||
|
- [ ] New: IBugCveMappingService.cs + implementations (Task 3.2)
|
||||||
|
|
||||||
|
### B. Dependency Updates
|
||||||
|
```xml
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\StellaOps.VersionComparison\StellaOps.VersionComparison.csproj" />
|
||||||
|
<ProjectReference Include="..\StellaOps.DistroIntel\StellaOps.DistroIntel.csproj" />
|
||||||
|
<ProjectReference Include="..\StellaOps.BugTracking\StellaOps.BugTracking.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
```
|
||||||
|
|
||||||
|
### C. Configuration Changes
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"BackportResolver": {
|
||||||
|
"EnableDerivativeMapping": true,
|
||||||
|
"DerivativeConfidencePenalty": 0.05,
|
||||||
|
"BugTrackerCache": {
|
||||||
|
"TtlHours": 1,
|
||||||
|
"MaxEntries": 10000
|
||||||
|
},
|
||||||
|
"TierTimeouts": {
|
||||||
|
"Tier1Ms": 500,
|
||||||
|
"Tier2Ms": 200,
|
||||||
|
"Tier3Ms": 300,
|
||||||
|
"Tier4Ms": 2000,
|
||||||
|
"Tier5Ms": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**End of Sprint Document**
|
||||||
Reference in New Issue
Block a user