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