Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.

This commit is contained in:
StellaOps Bot
2025-12-26 21:54:17 +02:00
parent 335ff7da16
commit c2b9cd8d1f
3717 changed files with 264714 additions and 48202 deletions

View File

@@ -190,6 +190,83 @@ public sealed class ReachabilityFactsSignalsClient : IReachabilityFactsSignalsCl
return false;
}
}
/// <inheritdoc />
public async Task<ReachabilityFactWithSubgraph?> GetWithSubgraphAsync(
string subjectKey,
string? cveId = null,
CancellationToken cancellationToken = default)
{
ArgumentException.ThrowIfNullOrWhiteSpace(subjectKey);
using var activity = PolicyEngineTelemetry.ActivitySource.StartActivity(
"signals_client.get_fact_with_subgraph",
ActivityKind.Client);
activity?.SetTag("signals.subject_key", subjectKey);
if (cveId is not null)
{
activity?.SetTag("signals.cve_id", cveId);
}
// Get base reachability fact from Signals
var fact = await GetBySubjectAsync(subjectKey, cancellationToken).ConfigureAwait(false);
if (fact is null)
{
_logger.LogDebug("No reachability fact found for subject {SubjectKey}", subjectKey);
return null;
}
if (string.IsNullOrEmpty(fact.CallgraphId))
{
_logger.LogDebug(
"Reachability fact for subject {SubjectKey} has no callgraph ID",
subjectKey);
return new ReachabilityFactWithSubgraph(fact, null);
}
// Fetch subgraph slice from ReachGraph Store
var sliceQuery = cveId is not null
? $"?cve={Uri.EscapeDataString(cveId)}"
: "";
try
{
var slicePath = _options.ReachGraphStoreBaseUri is not null
? $"v1/reachgraphs/{Uri.EscapeDataString(fact.CallgraphId)}/slice{sliceQuery}"
: $"reachgraph/v1/reachgraphs/{Uri.EscapeDataString(fact.CallgraphId)}/slice{sliceQuery}";
var response = await _httpClient.GetAsync(slicePath, cancellationToken).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
_logger.LogWarning(
"Failed to fetch subgraph slice for callgraph {CallgraphId}: {StatusCode}",
fact.CallgraphId,
response.StatusCode);
return new ReachabilityFactWithSubgraph(fact, null);
}
var slice = await response.Content
.ReadFromJsonAsync<ReachGraphSlice>(SerializerOptions, cancellationToken)
.ConfigureAwait(false);
_logger.LogDebug(
"Fetched subgraph slice for callgraph {CallgraphId}: {NodeCount} nodes, {PathCount} paths",
fact.CallgraphId,
slice?.NodeCount ?? 0,
slice?.Paths?.Count ?? 0);
return new ReachabilityFactWithSubgraph(fact, slice);
}
catch (HttpRequestException ex)
{
_logger.LogWarning(
ex,
"Error fetching subgraph slice for callgraph {CallgraphId}",
fact.CallgraphId);
return new ReachabilityFactWithSubgraph(fact, null);
}
}
}
/// <summary>
@@ -207,6 +284,12 @@ public sealed class ReachabilityFactsSignalsClientOptions
/// </summary>
public Uri? BaseUri { get; set; }
/// <summary>
/// Base URI for the ReachGraph Store service.
/// If null, uses the same base URI as Signals.
/// </summary>
public Uri? ReachGraphStoreBaseUri { get; set; }
/// <summary>
/// Maximum concurrent requests for batch operations.
/// Default: 10.