Refactor code structure for improved readability and maintainability; optimize performance in key functions.

This commit is contained in:
master
2025-12-22 19:06:31 +02:00
parent dfaa2079aa
commit 4602ccc3a3
1444 changed files with 109919 additions and 8058 deletions

View File

@@ -0,0 +1,433 @@
using System.Diagnostics;
using Microsoft.Extensions.Logging;
namespace StellaOps.Scanner.Orchestration.Fidelity;
public interface IFidelityAwareAnalyzer
{
Task<FidelityAnalysisResult> AnalyzeAsync(
AnalysisRequest request,
FidelityLevel level,
CancellationToken ct);
Task<FidelityUpgradeResult> UpgradeFidelityAsync(
Guid findingId,
FidelityLevel targetLevel,
CancellationToken ct);
}
public sealed class FidelityAwareAnalyzer : IFidelityAwareAnalyzer
{
private readonly ICallGraphExtractor _callGraphExtractor;
private readonly IRuntimeCorrelator _runtimeCorrelator;
private readonly IBinaryMapper _binaryMapper;
private readonly IPackageMatcher _packageMatcher;
private readonly IAnalysisRepository _repository;
private readonly ILogger<FidelityAwareAnalyzer> _logger;
public FidelityAwareAnalyzer(
ICallGraphExtractor callGraphExtractor,
IRuntimeCorrelator runtimeCorrelator,
IBinaryMapper binaryMapper,
IPackageMatcher packageMatcher,
IAnalysisRepository repository,
ILogger<FidelityAwareAnalyzer> logger)
{
_callGraphExtractor = callGraphExtractor;
_runtimeCorrelator = runtimeCorrelator;
_binaryMapper = binaryMapper;
_packageMatcher = packageMatcher;
_repository = repository;
_logger = logger;
}
public async Task<FidelityAnalysisResult> AnalyzeAsync(
AnalysisRequest request,
FidelityLevel level,
CancellationToken ct)
{
var config = FidelityConfiguration.FromLevel(level);
var stopwatch = Stopwatch.StartNew();
using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
cts.CancelAfter(config.Timeout);
try
{
// Level 1: Package matching (always done)
var packageResult = await _packageMatcher.MatchAsync(request, cts.Token);
if (level == FidelityLevel.Quick)
{
return BuildResult(packageResult, config, stopwatch.Elapsed);
}
// Level 2: Call graph analysis (Standard and Deep)
CallGraphResult? callGraphResult = null;
if (config.EnableCallGraph)
{
var languages = config.TargetLanguages ?? request.DetectedLanguages;
callGraphResult = await _callGraphExtractor.ExtractAsync(
request,
languages,
config.MaxCallGraphDepth,
cts.Token);
}
if (level == FidelityLevel.Standard)
{
return BuildResult(packageResult, callGraphResult, config, stopwatch.Elapsed);
}
// Level 3: Binary mapping and runtime (Deep only)
BinaryMappingResult? binaryResult = null;
RuntimeCorrelationResult? runtimeResult = null;
if (config.EnableBinaryMapping)
{
binaryResult = await _binaryMapper.MapAsync(request, cts.Token);
}
if (config.EnableRuntimeCorrelation)
{
runtimeResult = await _runtimeCorrelator.CorrelateAsync(request, cts.Token);
}
return BuildResult(
packageResult,
callGraphResult,
binaryResult,
runtimeResult,
config,
stopwatch.Elapsed);
}
catch (OperationCanceledException) when (cts.IsCancellationRequested && !ct.IsCancellationRequested)
{
_logger.LogWarning(
"Analysis timeout at fidelity {Level} after {Elapsed}",
level, stopwatch.Elapsed);
return BuildTimeoutResult(level, config, stopwatch.Elapsed);
}
}
public async Task<FidelityUpgradeResult> UpgradeFidelityAsync(
Guid findingId,
FidelityLevel targetLevel,
CancellationToken ct)
{
// Load existing analysis
var existing = await _repository.GetAnalysisAsync(findingId, ct);
if (existing is null)
{
return FidelityUpgradeResult.NotFound(findingId);
}
if (existing.FidelityLevel >= targetLevel)
{
return FidelityUpgradeResult.AlreadyAtLevel(existing);
}
// Perform incremental upgrade
var request = existing.ToAnalysisRequest();
var result = await AnalyzeAsync(request, targetLevel, ct);
// Merge with existing
var merged = MergeResults(existing, result);
// Persist upgraded result
await _repository.SaveAnalysisAsync(merged, ct);
return new FidelityUpgradeResult
{
Success = true,
FindingId = findingId,
PreviousLevel = existing.FidelityLevel,
NewLevel = targetLevel,
ConfidenceImprovement = merged.Confidence - existing.Confidence,
NewResult = merged
};
}
private FidelityAnalysisResult BuildResult(
PackageMatchResult packageResult,
FidelityConfiguration config,
TimeSpan elapsed)
{
var confidence = config.BaseConfidence;
// Adjust confidence based on match quality
if (packageResult.HasExactMatch)
confidence += 0.1m;
return new FidelityAnalysisResult
{
FidelityLevel = config.Level,
Confidence = Math.Min(confidence, 1.0m),
IsReachable = null, // Unknown at Quick level
PackageMatches = packageResult.Matches,
CallGraph = null,
BinaryMapping = null,
RuntimeCorrelation = null,
AnalysisTime = elapsed,
TimedOut = false,
CanUpgrade = true,
UpgradeRecommendation = "Upgrade to Standard for call graph analysis"
};
}
private FidelityAnalysisResult BuildResult(
PackageMatchResult packageResult,
CallGraphResult? callGraphResult,
FidelityConfiguration config,
TimeSpan elapsed)
{
var confidence = config.BaseConfidence;
// Adjust based on call graph completeness
if (callGraphResult?.IsComplete == true)
confidence += 0.15m;
var isReachable = callGraphResult?.HasPathToVulnerable;
return new FidelityAnalysisResult
{
FidelityLevel = config.Level,
Confidence = Math.Min(confidence, 1.0m),
IsReachable = isReachable,
PackageMatches = packageResult.Matches,
CallGraph = callGraphResult,
BinaryMapping = null,
RuntimeCorrelation = null,
AnalysisTime = elapsed,
TimedOut = false,
CanUpgrade = true,
UpgradeRecommendation = isReachable == true
? "Upgrade to Deep for runtime verification"
: "Upgrade to Deep for binary mapping confirmation"
};
}
private FidelityAnalysisResult BuildResult(
PackageMatchResult packageResult,
CallGraphResult? callGraphResult,
BinaryMappingResult? binaryResult,
RuntimeCorrelationResult? runtimeResult,
FidelityConfiguration config,
TimeSpan elapsed)
{
var confidence = config.BaseConfidence;
// Adjust based on runtime corroboration
if (runtimeResult?.HasCorroboration == true)
confidence = 0.95m;
else if (binaryResult?.HasMapping == true)
confidence += 0.05m;
var isReachable = DetermineReachability(
callGraphResult,
binaryResult,
runtimeResult);
return new FidelityAnalysisResult
{
FidelityLevel = config.Level,
Confidence = Math.Min(confidence, 1.0m),
IsReachable = isReachable,
PackageMatches = packageResult.Matches,
CallGraph = callGraphResult,
BinaryMapping = binaryResult,
RuntimeCorrelation = runtimeResult,
AnalysisTime = elapsed,
TimedOut = false,
CanUpgrade = false,
UpgradeRecommendation = null
};
}
private static bool? DetermineReachability(
CallGraphResult? callGraph,
BinaryMappingResult? binary,
RuntimeCorrelationResult? runtime)
{
// Runtime is authoritative
if (runtime?.WasExecuted == true)
return true;
if (runtime?.WasExecuted == false && runtime.ObservationCount > 100)
return false;
// Fall back to call graph
if (callGraph?.HasPathToVulnerable == true)
return true;
if (callGraph?.HasPathToVulnerable == false && callGraph.IsComplete)
return false;
return null; // Unknown
}
private FidelityAnalysisResult BuildTimeoutResult(
FidelityLevel attemptedLevel,
FidelityConfiguration config,
TimeSpan elapsed)
{
return new FidelityAnalysisResult
{
FidelityLevel = attemptedLevel,
Confidence = 0.3m,
IsReachable = null,
PackageMatches = [],
CallGraph = null,
BinaryMapping = null,
RuntimeCorrelation = null,
AnalysisTime = elapsed,
TimedOut = true,
CanUpgrade = false,
UpgradeRecommendation = "Analysis timed out. Try with smaller scope."
};
}
private FidelityAnalysisResult MergeResults(
FidelityAnalysisResult existing,
FidelityAnalysisResult upgraded)
{
// Take the upgraded result but preserve any existing data not replaced
return new FidelityAnalysisResult
{
FidelityLevel = upgraded.FidelityLevel,
Confidence = upgraded.Confidence,
IsReachable = upgraded.IsReachable ?? existing.IsReachable,
PackageMatches = upgraded.PackageMatches,
CallGraph = upgraded.CallGraph ?? existing.CallGraph,
BinaryMapping = upgraded.BinaryMapping ?? existing.BinaryMapping,
RuntimeCorrelation = upgraded.RuntimeCorrelation ?? existing.RuntimeCorrelation,
AnalysisTime = existing.AnalysisTime + upgraded.AnalysisTime,
TimedOut = upgraded.TimedOut,
CanUpgrade = upgraded.CanUpgrade,
UpgradeRecommendation = upgraded.UpgradeRecommendation
};
}
}
public sealed record FidelityAnalysisResult
{
public required FidelityLevel FidelityLevel { get; init; }
public required decimal Confidence { get; init; }
public bool? IsReachable { get; init; }
public required IReadOnlyList<PackageMatch> PackageMatches { get; init; }
public CallGraphResult? CallGraph { get; init; }
public BinaryMappingResult? BinaryMapping { get; init; }
public RuntimeCorrelationResult? RuntimeCorrelation { get; init; }
public required TimeSpan AnalysisTime { get; init; }
public required bool TimedOut { get; init; }
public required bool CanUpgrade { get; init; }
public string? UpgradeRecommendation { get; init; }
public AnalysisRequest ToAnalysisRequest()
{
// Convert back to analysis request for upgrade scenarios
return new AnalysisRequest
{
// Populate from existing result
};
}
}
public sealed record FidelityUpgradeResult
{
public required bool Success { get; init; }
public Guid FindingId { get; init; }
public FidelityLevel? PreviousLevel { get; init; }
public FidelityLevel? NewLevel { get; init; }
public decimal ConfidenceImprovement { get; init; }
public FidelityAnalysisResult? NewResult { get; init; }
public string? Error { get; init; }
public static FidelityUpgradeResult NotFound(Guid id) => new()
{
Success = false,
FindingId = id,
Error = "Finding not found"
};
public static FidelityUpgradeResult AlreadyAtLevel(FidelityAnalysisResult existing) => new()
{
Success = true,
PreviousLevel = existing.FidelityLevel,
NewLevel = existing.FidelityLevel,
ConfidenceImprovement = 0,
NewResult = existing
};
}
// Supporting interfaces and types
public interface ICallGraphExtractor
{
Task<CallGraphResult> ExtractAsync(
AnalysisRequest request,
IReadOnlyList<string> languages,
int maxDepth,
CancellationToken ct);
}
public interface IRuntimeCorrelator
{
Task<RuntimeCorrelationResult> CorrelateAsync(
AnalysisRequest request,
CancellationToken ct);
}
public interface IBinaryMapper
{
Task<BinaryMappingResult> MapAsync(
AnalysisRequest request,
CancellationToken ct);
}
public interface IPackageMatcher
{
Task<PackageMatchResult> MatchAsync(
AnalysisRequest request,
CancellationToken ct);
}
public interface IAnalysisRepository
{
Task<FidelityAnalysisResult?> GetAnalysisAsync(Guid findingId, CancellationToken ct);
Task SaveAnalysisAsync(FidelityAnalysisResult result, CancellationToken ct);
}
public sealed record AnalysisRequest
{
public IReadOnlyList<string> DetectedLanguages { get; init; } = Array.Empty<string>();
}
public sealed record PackageMatchResult
{
public bool HasExactMatch { get; init; }
public IReadOnlyList<PackageMatch> Matches { get; init; } = Array.Empty<PackageMatch>();
}
public sealed record PackageMatch
{
public required string PackageName { get; init; }
public required string Version { get; init; }
}
public sealed record CallGraphResult
{
public bool IsComplete { get; init; }
public bool? HasPathToVulnerable { get; init; }
}
public sealed record BinaryMappingResult
{
public bool HasMapping { get; init; }
}
public sealed record RuntimeCorrelationResult
{
public bool? WasExecuted { get; init; }
public int ObservationCount { get; init; }
public bool HasCorroboration { get; init; }
}

View File

@@ -0,0 +1,112 @@
namespace StellaOps.Scanner.Orchestration.Fidelity;
/// <summary>
/// Analysis fidelity level controlling depth vs speed tradeoff.
/// </summary>
public enum FidelityLevel
{
/// <summary>
/// Fast heuristic analysis. Uses package-level matching only.
/// ~10x faster than Standard. Lower confidence.
/// </summary>
Quick,
/// <summary>
/// Standard analysis. Includes call graph for top languages.
/// Balanced speed and accuracy.
/// </summary>
Standard,
/// <summary>
/// Deep analysis. Full call graph, runtime correlation, binary mapping.
/// Highest confidence but slowest.
/// </summary>
Deep
}
/// <summary>
/// Configuration for each fidelity level.
/// </summary>
public sealed record FidelityConfiguration
{
public required FidelityLevel Level { get; init; }
/// <summary>
/// Whether to perform call graph extraction.
/// </summary>
public bool EnableCallGraph { get; init; }
/// <summary>
/// Whether to correlate with runtime evidence.
/// </summary>
public bool EnableRuntimeCorrelation { get; init; }
/// <summary>
/// Whether to perform binary mapping.
/// </summary>
public bool EnableBinaryMapping { get; init; }
/// <summary>
/// Maximum call graph depth.
/// </summary>
public int MaxCallGraphDepth { get; init; }
/// <summary>
/// Timeout for analysis.
/// </summary>
public TimeSpan Timeout { get; init; }
/// <summary>
/// Base confidence for this fidelity level.
/// </summary>
public decimal BaseConfidence { get; init; }
/// <summary>
/// Languages to analyze (null = all).
/// </summary>
public IReadOnlyList<string>? TargetLanguages { get; init; }
public static FidelityConfiguration Quick => new()
{
Level = FidelityLevel.Quick,
EnableCallGraph = false,
EnableRuntimeCorrelation = false,
EnableBinaryMapping = false,
MaxCallGraphDepth = 0,
Timeout = TimeSpan.FromSeconds(30),
BaseConfidence = 0.5m,
TargetLanguages = null
};
public static FidelityConfiguration Standard => new()
{
Level = FidelityLevel.Standard,
EnableCallGraph = true,
EnableRuntimeCorrelation = false,
EnableBinaryMapping = false,
MaxCallGraphDepth = 10,
Timeout = TimeSpan.FromMinutes(5),
BaseConfidence = 0.75m,
TargetLanguages = ["java", "dotnet", "python", "go", "node"]
};
public static FidelityConfiguration Deep => new()
{
Level = FidelityLevel.Deep,
EnableCallGraph = true,
EnableRuntimeCorrelation = true,
EnableBinaryMapping = true,
MaxCallGraphDepth = 50,
Timeout = TimeSpan.FromMinutes(30),
BaseConfidence = 0.9m,
TargetLanguages = null
};
public static FidelityConfiguration FromLevel(FidelityLevel level) => level switch
{
FidelityLevel.Quick => Quick,
FidelityLevel.Standard => Standard,
FidelityLevel.Deep => Deep,
_ => Standard
};
}