up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-26 07:47:08 +02:00
parent 56e2f64d07
commit 1c782897f7
184 changed files with 8991 additions and 649 deletions

View File

@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using StellaOps.Signals.Models;
using StellaOps.Signals.Persistence;
namespace StellaOps.Signals.Services;
internal sealed class UnknownsIngestionService : IUnknownsIngestionService
{
private readonly IUnknownsRepository repository;
private readonly TimeProvider timeProvider;
private readonly ILogger<UnknownsIngestionService> logger;
public UnknownsIngestionService(IUnknownsRepository repository, TimeProvider timeProvider, ILogger<UnknownsIngestionService> logger)
{
this.repository = repository ?? throw new ArgumentNullException(nameof(repository));
this.timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task<UnknownsIngestResponse> IngestAsync(UnknownsIngestRequest request, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
if (request.Subject is null)
{
throw new UnknownsValidationException("Subject is required.");
}
if (string.IsNullOrWhiteSpace(request.CallgraphId))
{
throw new UnknownsValidationException("callgraphId is required.");
}
if (request.Unknowns is null || request.Unknowns.Count == 0)
{
throw new UnknownsValidationException("Unknowns list must not be empty.");
}
var subjectKey = request.Subject.ToSubjectKey();
if (string.IsNullOrWhiteSpace(subjectKey))
{
throw new UnknownsValidationException("Subject must include scanId, imageDigest, or component/version.");
}
var now = timeProvider.GetUtcNow();
var normalized = new List<UnknownSymbolDocument>();
foreach (var entry in request.Unknowns)
{
if (entry is null)
{
continue;
}
var hasContent = !(string.IsNullOrWhiteSpace(entry.SymbolId)
&& string.IsNullOrWhiteSpace(entry.CodeId)
&& string.IsNullOrWhiteSpace(entry.Purl)
&& string.IsNullOrWhiteSpace(entry.EdgeFrom)
&& string.IsNullOrWhiteSpace(entry.EdgeTo));
if (!hasContent)
{
continue;
}
normalized.Add(new UnknownSymbolDocument
{
SubjectKey = subjectKey,
CallgraphId = request.CallgraphId,
SymbolId = entry.SymbolId?.Trim(),
CodeId = entry.CodeId?.Trim(),
Purl = entry.Purl?.Trim(),
EdgeFrom = entry.EdgeFrom?.Trim(),
EdgeTo = entry.EdgeTo?.Trim(),
Reason = entry.Reason?.Trim(),
CreatedAt = now
});
}
if (normalized.Count == 0)
{
throw new UnknownsValidationException("Unknown entries must include at least one symbolId, codeId, purl, or edge.");
}
await repository.UpsertAsync(subjectKey, normalized, cancellationToken).ConfigureAwait(false);
logger.LogInformation("Stored {Count} unknown symbols for subject {SubjectKey}", normalized.Count, subjectKey);
return new UnknownsIngestResponse
{
SubjectKey = subjectKey,
UnknownsCount = normalized.Count
};
}
}