Stabilzie modules

This commit is contained in:
master
2026-02-16 07:32:38 +02:00
parent ab794e167c
commit 45c0f1bb59
45 changed files with 3055 additions and 156 deletions

View File

@@ -263,6 +263,99 @@ public sealed record SliceEdge
public required string To { get; init; }
}
/// <summary>
/// HTTP implementation of IReachGraphSliceClient that calls the ReachGraph service API.
/// </summary>
public sealed class HttpReachGraphSliceClient : IReachGraphSliceClient
{
private readonly HttpClient _httpClient;
private readonly ILogger<HttpReachGraphSliceClient> _logger;
/// <summary>
/// Creates a new HTTP-backed ReachGraph slice client.
/// </summary>
/// <param name="httpClient">Pre-configured HttpClient targeting ReachGraph base URL.</param>
/// <param name="logger">Logger.</param>
public HttpReachGraphSliceClient(
HttpClient httpClient,
ILogger<HttpReachGraphSliceClient> logger)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <inheritdoc />
public async Task<CveSliceResult?> SliceByCveAsync(
string digest,
string cveId,
string tenantId,
int maxPaths = 5,
CancellationToken ct = default)
{
_logger.LogDebug("Querying ReachGraph slice-by-CVE: {CveId} for {Digest}", cveId, digest);
try
{
var url = $"api/v1/slice/cve?digest={Uri.EscapeDataString(digest)}&cveId={Uri.EscapeDataString(cveId)}&tenantId={Uri.EscapeDataString(tenantId)}&maxPaths={maxPaths}";
var response = await _httpClient.GetAsync(url, ct);
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
_logger.LogDebug("No slice data found for CVE {CveId}", cveId);
return null;
}
response.EnsureSuccessStatusCode();
return await System.Text.Json.JsonSerializer.DeserializeAsync<CveSliceResult>(
await response.Content.ReadAsStreamAsync(ct),
new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true },
ct);
}
catch (HttpRequestException ex)
{
_logger.LogWarning(ex, "Failed to query ReachGraph for CVE {CveId}", cveId);
return null;
}
}
/// <inheritdoc />
public async Task<SliceResult?> SliceByEntrypointAsync(
string digest,
string entrypointPattern,
string tenantId,
int maxDepth = 10,
CancellationToken ct = default)
{
_logger.LogDebug("Querying ReachGraph slice-by-entrypoint: {Pattern} for {Digest}", entrypointPattern, digest);
try
{
var url = $"api/v1/slice/entrypoint?digest={Uri.EscapeDataString(digest)}&pattern={Uri.EscapeDataString(entrypointPattern)}&tenantId={Uri.EscapeDataString(tenantId)}&maxDepth={maxDepth}";
var response = await _httpClient.GetAsync(url, ct);
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
response.EnsureSuccessStatusCode();
return await System.Text.Json.JsonSerializer.DeserializeAsync<SliceResult>(
await response.Content.ReadAsStreamAsync(ct),
new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true },
ct);
}
catch (HttpRequestException ex)
{
_logger.LogWarning(ex, "Failed to query ReachGraph for entrypoint {Pattern}", entrypointPattern);
return null;
}
}
}
/// <summary>
/// Null implementation of IReachGraphSliceClient for testing.
/// </summary>