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,20 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using StellaOps.AdvisoryAI.Caching;
using StellaOps.AdvisoryAI.DependencyInjection;
using StellaOps.AdvisoryAI.Queue;
using StellaOps.AdvisoryAI.Worker.Services;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMetrics();
builder.Services.AddAdvisoryPipeline(options => builder.Configuration.GetSection("AdvisoryAI:Pipeline").Bind(options));
builder.Services.AddAdvisoryPipelineInfrastructure();
builder.Services.Configure<AdvisoryPlanCacheOptions>(builder.Configuration.GetSection("AdvisoryAI:PlanCache"));
builder.Services.Configure<AdvisoryTaskQueueOptions>(builder.Configuration.GetSection("AdvisoryAI:TaskQueue"));
builder.Services.AddHostedService<AdvisoryTaskWorker>();
var host = builder.Build();
await host.RunAsync();

View File

@@ -0,0 +1,87 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using StellaOps.AdvisoryAI.Caching;
using StellaOps.AdvisoryAI.Metrics;
using StellaOps.AdvisoryAI.Orchestration;
using StellaOps.AdvisoryAI.Queue;
using StellaOps.AdvisoryAI.Execution;
namespace StellaOps.AdvisoryAI.Worker.Services;
internal sealed class AdvisoryTaskWorker : BackgroundService
{
private readonly IAdvisoryTaskQueue _queue;
private readonly IAdvisoryPlanCache _cache;
private readonly IAdvisoryPipelineOrchestrator _orchestrator;
private readonly AdvisoryPipelineMetrics _metrics;
private readonly IAdvisoryPipelineExecutor _executor;
private readonly TimeProvider _timeProvider;
private readonly ILogger<AdvisoryTaskWorker> _logger;
public AdvisoryTaskWorker(
IAdvisoryTaskQueue queue,
IAdvisoryPlanCache cache,
IAdvisoryPipelineOrchestrator orchestrator,
AdvisoryPipelineMetrics metrics,
IAdvisoryPipelineExecutor executor,
TimeProvider timeProvider,
ILogger<AdvisoryTaskWorker> logger)
{
_queue = queue ?? throw new ArgumentNullException(nameof(queue));
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
_orchestrator = orchestrator ?? throw new ArgumentNullException(nameof(orchestrator));
_metrics = metrics ?? throw new ArgumentNullException(nameof(metrics));
_executor = executor ?? throw new ArgumentNullException(nameof(executor));
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Advisory pipeline worker started");
while (!stoppingToken.IsCancellationRequested)
{
try
{
var message = await _queue.DequeueAsync(stoppingToken).ConfigureAwait(false);
if (message is null)
{
continue;
}
AdvisoryTaskPlan? plan = await _cache.TryGetAsync(message.PlanCacheKey, stoppingToken).ConfigureAwait(false);
var fromCache = plan is not null && !message.Request.ForceRefresh;
if (!fromCache)
{
var start = _timeProvider.GetTimestamp();
plan = await _orchestrator.CreatePlanAsync(message.Request, stoppingToken).ConfigureAwait(false);
await _cache.SetAsync(plan.CacheKey, plan, stoppingToken).ConfigureAwait(false);
var elapsed = _timeProvider.GetElapsedTime(start);
_metrics.RecordPlanCreated(elapsed.TotalSeconds, message.Request.TaskType);
}
_logger.LogInformation(
"Processed advisory task {TaskType} for advisory {AdvisoryKey} (cache:{Cache})",
message.Request.TaskType,
message.Request.AdvisoryKey,
fromCache);
await _executor.ExecuteAsync(plan, message, fromCache, stoppingToken).ConfigureAwait(false);
_metrics.RecordPlanProcessed(message.Request.TaskType, fromCache);
}
catch (OperationCanceledException)
{
// graceful shutdown
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing advisory task queue message");
await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken).ConfigureAwait(false);
}
}
_logger.LogInformation("Advisory pipeline worker stopping");
}
}

View File

@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.AdvisoryAI\StellaOps.AdvisoryAI.csproj" />
</ItemGroup>
</Project>