Add unit tests for SBOM ingestion and transformation
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Implement `SbomIngestServiceCollectionExtensionsTests` to verify the SBOM ingestion pipeline exports snapshots correctly.
- Create `SbomIngestTransformerTests` to ensure the transformation produces expected nodes and edges, including deduplication of license nodes and normalization of timestamps.
- Add `SbomSnapshotExporterTests` to test the export functionality for manifest, adjacency, nodes, and edges.
- Introduce `VexOverlayTransformerTests` to validate the transformation of VEX nodes and edges.
- Set up project file for the test project with necessary dependencies and configurations.
- Include JSON fixture files for testing purposes.
This commit is contained in:
master
2025-11-04 07:49:39 +02:00
parent f72c5c513a
commit 2eb6852d34
491 changed files with 39445 additions and 3917 deletions

View File

@@ -0,0 +1,79 @@
using Microsoft.Extensions.Logging;
using StellaOps.AdvisoryAI.Guardrails;
using StellaOps.AdvisoryAI.Outputs;
using StellaOps.AdvisoryAI.Orchestration;
using StellaOps.AdvisoryAI.Prompting;
using StellaOps.AdvisoryAI.Metrics;
using StellaOps.AdvisoryAI.Queue;
namespace StellaOps.AdvisoryAI.Execution;
public interface IAdvisoryPipelineExecutor
{
Task ExecuteAsync(
AdvisoryTaskPlan plan,
AdvisoryTaskQueueMessage message,
bool planFromCache,
CancellationToken cancellationToken);
}
internal sealed class AdvisoryPipelineExecutor : IAdvisoryPipelineExecutor
{
private readonly IAdvisoryPromptAssembler _promptAssembler;
private readonly IAdvisoryGuardrailPipeline _guardrailPipeline;
private readonly IAdvisoryOutputStore _outputStore;
private readonly AdvisoryPipelineMetrics _metrics;
private readonly TimeProvider _timeProvider;
private readonly ILogger<AdvisoryPipelineExecutor>? _logger;
public AdvisoryPipelineExecutor(
IAdvisoryPromptAssembler promptAssembler,
IAdvisoryGuardrailPipeline guardrailPipeline,
IAdvisoryOutputStore outputStore,
AdvisoryPipelineMetrics metrics,
TimeProvider timeProvider,
ILogger<AdvisoryPipelineExecutor>? logger = null)
{
_promptAssembler = promptAssembler ?? throw new ArgumentNullException(nameof(promptAssembler));
_guardrailPipeline = guardrailPipeline ?? throw new ArgumentNullException(nameof(guardrailPipeline));
_outputStore = outputStore ?? throw new ArgumentNullException(nameof(outputStore));
_metrics = metrics ?? throw new ArgumentNullException(nameof(metrics));
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
_logger = logger;
}
public async Task ExecuteAsync(
AdvisoryTaskPlan plan,
AdvisoryTaskQueueMessage message,
bool planFromCache,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(plan);
ArgumentNullException.ThrowIfNull(message);
var prompt = await _promptAssembler.AssembleAsync(plan, cancellationToken).ConfigureAwait(false);
var guardrailResult = await _guardrailPipeline.EvaluateAsync(prompt, cancellationToken).ConfigureAwait(false);
if (guardrailResult.Blocked)
{
_logger?.LogWarning(
"Guardrail blocked advisory pipeline output for {TaskType} on advisory {AdvisoryKey}",
plan.Request.TaskType,
plan.Request.AdvisoryKey);
}
var generatedAt = _timeProvider.GetUtcNow();
var output = AdvisoryPipelineOutput.Create(plan, prompt, guardrailResult, generatedAt, planFromCache);
await _outputStore.SaveAsync(output, cancellationToken).ConfigureAwait(false);
_metrics.RecordGuardrailResult(plan.Request.TaskType, guardrailResult.Blocked);
_metrics.RecordOutputStored(plan.Request.TaskType, planFromCache, guardrailResult.Blocked);
_logger?.LogInformation(
"Stored advisory pipeline output {CacheKey} (task {TaskType}, cache:{CacheHit}, guardrail_blocked:{Blocked})",
output.CacheKey,
plan.Request.TaskType,
planFromCache,
guardrailResult.Blocked);
}
}