Stabilzie modules
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user