sprints work

This commit is contained in:
master
2026-01-10 11:15:28 +02:00
parent a21d3dbc1f
commit 701eb6b21c
71 changed files with 10854 additions and 136 deletions

View File

@@ -0,0 +1,210 @@
// <copyright file="ReachabilityCoreBridge.cs" company="StellaOps">
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
// </copyright>
using StellaOps.Reachability.Core;
namespace StellaOps.Policy.Engine.ReachabilityFacts;
/// <summary>
/// Bridge between Reachability.Core types and Policy.Engine types.
/// Enables gradual migration from ReachabilityFact to HybridReachabilityResult.
/// Sprint: SPRINT_20260109_009_005 Task: Integrate Reachability.Core
/// </summary>
public static class ReachabilityCoreBridge
{
/// <summary>
/// Converts a <see cref="HybridReachabilityResult"/> to a <see cref="ReachabilityFact"/>.
/// Used to maintain backward compatibility with existing VEX emission.
/// </summary>
public static ReachabilityFact ToReachabilityFact(
HybridReachabilityResult result,
string tenantId,
string advisoryId)
{
ArgumentNullException.ThrowIfNull(result);
ArgumentException.ThrowIfNullOrEmpty(tenantId);
ArgumentException.ThrowIfNullOrEmpty(advisoryId);
var state = MapLatticeToState(result.LatticeState);
var method = DetermineMethod(result);
return new ReachabilityFact
{
Id = $"rf-{result.ContentDigest[7..23]}", // Use part of content digest as ID
TenantId = tenantId,
ComponentPurl = result.ArtifactDigest,
AdvisoryId = advisoryId,
State = state,
Confidence = (decimal)result.Confidence,
Score = ComputeScore(result),
HasRuntimeEvidence = result.RuntimeResult is not null,
Source = "StellaOps.Reachability.Core",
Method = method,
EvidenceRef = result.Evidence.Uris.Length > 0 ? result.Evidence.Uris[0] : null,
EvidenceHash = result.ContentDigest,
ComputedAt = result.ComputedAt,
ExpiresAt = result.ComputedAt.AddDays(7),
Metadata = BuildMetadata(result)
};
}
/// <summary>
/// Maps lattice state enum to string representation.
/// </summary>
public static string MapLatticeStateToString(LatticeState state)
{
return state switch
{
LatticeState.Unknown => "U",
LatticeState.StaticReachable => "SR",
LatticeState.StaticUnreachable => "SU",
LatticeState.RuntimeObserved => "RO",
LatticeState.RuntimeUnobserved => "RU",
LatticeState.ConfirmedReachable => "CR",
LatticeState.ConfirmedUnreachable => "CU",
LatticeState.Contested => "X",
_ => "U"
};
}
/// <summary>
/// Parses string lattice state to enum.
/// </summary>
public static LatticeState ParseLatticeState(string? state)
{
return state switch
{
"U" or null => LatticeState.Unknown,
"SR" => LatticeState.StaticReachable,
"SU" => LatticeState.StaticUnreachable,
"RO" => LatticeState.RuntimeObserved,
"RU" => LatticeState.RuntimeUnobserved,
"CR" => LatticeState.ConfirmedReachable,
"CU" => LatticeState.ConfirmedUnreachable,
"X" => LatticeState.Contested,
_ => LatticeState.Unknown
};
}
/// <summary>
/// Maps lattice state to triage bucket.
/// </summary>
public static string MapToBucket(LatticeState state)
{
return state switch
{
LatticeState.ConfirmedReachable or LatticeState.RuntimeObserved => "critical",
LatticeState.StaticReachable => "high",
LatticeState.Contested or LatticeState.Unknown => "medium",
LatticeState.RuntimeUnobserved => "low",
LatticeState.StaticUnreachable or LatticeState.ConfirmedUnreachable => "informational",
_ => "medium"
};
}
/// <summary>
/// Maps HybridReachabilityResult to VEX status.
/// </summary>
public static string MapToVexStatus(HybridReachabilityResult result)
{
return result.LatticeState switch
{
LatticeState.ConfirmedUnreachable or LatticeState.StaticUnreachable => "not_affected",
LatticeState.RuntimeUnobserved when result.Confidence >= 0.7 => "not_affected",
LatticeState.ConfirmedReachable or LatticeState.RuntimeObserved => "affected",
LatticeState.StaticReachable => "under_investigation",
_ => "under_investigation"
};
}
/// <summary>
/// Maps HybridReachabilityResult to VEX justification.
/// </summary>
public static string? MapToVexJustification(HybridReachabilityResult result)
{
return result.LatticeState switch
{
LatticeState.ConfirmedUnreachable or LatticeState.StaticUnreachable =>
"vulnerable_code_not_in_execute_path",
LatticeState.RuntimeUnobserved when result.Confidence >= 0.7 =>
"vulnerable_code_not_in_execute_path",
_ => null
};
}
private static ReachabilityState MapLatticeToState(LatticeState lattice)
{
return lattice switch
{
LatticeState.ConfirmedReachable or
LatticeState.RuntimeObserved or
LatticeState.StaticReachable => ReachabilityState.Reachable,
LatticeState.ConfirmedUnreachable or
LatticeState.StaticUnreachable or
LatticeState.RuntimeUnobserved => ReachabilityState.Unreachable,
LatticeState.Contested => ReachabilityState.UnderInvestigation,
_ => ReachabilityState.Unknown
};
}
private static AnalysisMethod DetermineMethod(HybridReachabilityResult result)
{
var hasStatic = result.StaticResult is not null;
var hasRuntime = result.RuntimeResult is not null;
return (hasStatic, hasRuntime) switch
{
(true, true) => AnalysisMethod.Hybrid,
(true, false) => AnalysisMethod.Static,
(false, true) => AnalysisMethod.Dynamic,
_ => AnalysisMethod.Static // Default to static when no analysis available
};
}
private static decimal ComputeScore(HybridReachabilityResult result)
{
// Score based on lattice state - higher means more reachable
return result.LatticeState switch
{
LatticeState.ConfirmedReachable => 1.0m,
LatticeState.RuntimeObserved => 0.9m,
LatticeState.StaticReachable => 0.7m,
LatticeState.Contested => 0.5m,
LatticeState.Unknown => 0.5m,
LatticeState.RuntimeUnobserved => 0.3m,
LatticeState.StaticUnreachable => 0.1m,
LatticeState.ConfirmedUnreachable => 0.0m,
_ => 0.5m
};
}
private static Dictionary<string, object?> BuildMetadata(HybridReachabilityResult result)
{
var metadata = new Dictionary<string, object?>
{
["lattice_state"] = MapLatticeStateToString(result.LatticeState),
["symbol_canonical_id"] = result.Symbol.CanonicalId,
["symbol_purl"] = result.Symbol.Purl,
["symbol_type"] = result.Symbol.Type,
["symbol_method"] = result.Symbol.Method
};
if (result.StaticResult is not null)
{
metadata["static_reachable"] = result.StaticResult.IsReachable;
metadata["static_path_count"] = result.StaticResult.PathCount;
}
if (result.RuntimeResult is not null)
{
metadata["runtime_observed"] = result.RuntimeResult.WasObserved;
metadata["runtime_hit_count"] = result.RuntimeResult.HitCount;
}
return metadata;
}
}

View File

@@ -26,6 +26,7 @@
<ProjectReference Include="../../__Libraries/StellaOps.Canonical.Json/StellaOps.Canonical.Json.csproj" />
<ProjectReference Include="../../Router/__Libraries/StellaOps.Messaging/StellaOps.Messaging.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Provcache/StellaOps.Provcache.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Reachability.Core/StellaOps.Reachability.Core.csproj" />
<ProjectReference Include="../__Libraries/StellaOps.Policy/StellaOps.Policy.csproj" />
<ProjectReference Include="../__Libraries/StellaOps.Policy.Determinization/StellaOps.Policy.Determinization.csproj" />
<ProjectReference Include="../__Libraries/StellaOps.Policy.Exceptions/StellaOps.Policy.Exceptions.csproj" />