Some checks failed
Lighthouse CI / Lighthouse Audit (push) Has been cancelled
Lighthouse CI / Axe Accessibility Audit (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
sm-remote-ci / build-and-test (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
102 lines
3.5 KiB
C#
102 lines
3.5 KiB
C#
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,
|
|
UpdatedAt = now,
|
|
LastAnalyzedAt = 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
|
|
};
|
|
}
|
|
}
|