save checkpoint

This commit is contained in:
master
2026-02-11 01:32:14 +02:00
parent 5593212b41
commit cf5b72974f
2316 changed files with 68799 additions and 3808 deletions

View File

@@ -133,6 +133,8 @@ internal static class SbomEndpoints
sbomDocument,
format,
contentDigest,
snapshot.Target.Digest,
parsed.Value,
cancellationToken).ConfigureAwait(false);
sbomDocument.Dispose();

View File

@@ -0,0 +1,174 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using StellaOps.Scanner.WebService.Constants;
using StellaOps.Scanner.WebService.Contracts;
using StellaOps.Scanner.WebService.Infrastructure;
using StellaOps.Scanner.WebService.Security;
using StellaOps.Scanner.WebService.Services;
namespace StellaOps.Scanner.WebService.Endpoints;
internal static class SbomHotLookupEndpoints
{
public static void MapSbomHotLookupEndpoints(this RouteGroupBuilder sbomGroup)
{
ArgumentNullException.ThrowIfNull(sbomGroup);
var hotLookup = sbomGroup.MapGroup("/hot-lookup");
hotLookup.MapGet("/payload/{payloadDigest}/latest", HandleGetLatestByPayloadDigestAsync)
.WithName("scanner.sbom.hotlookup.latest-by-payload")
.WithTags("SBOM")
.Produces<SbomHotLookupLatestResponseDto>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound)
.Produces(StatusCodes.Status400BadRequest)
.RequireAuthorization(ScannerPolicies.ScansRead);
hotLookup.MapGet("/components", HandleSearchComponentsAsync)
.WithName("scanner.sbom.hotlookup.components")
.WithTags("SBOM")
.Produces<SbomHotLookupComponentSearchResponseDto>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status400BadRequest)
.RequireAuthorization(ScannerPolicies.ScansRead);
hotLookup.MapGet("/pending-triage", HandleSearchPendingTriageAsync)
.WithName("scanner.sbom.hotlookup.pending-triage")
.WithTags("SBOM")
.Produces<SbomHotLookupPendingSearchResponseDto>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status400BadRequest)
.RequireAuthorization(ScannerPolicies.ScansRead);
}
private static async Task<IResult> HandleGetLatestByPayloadDigestAsync(
string payloadDigest,
ISbomHotLookupService hotLookupService,
HttpContext context,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(hotLookupService);
if (string.IsNullOrWhiteSpace(payloadDigest))
{
return ProblemResultFactory.Create(
context,
ProblemTypes.Validation,
"Invalid payload digest",
StatusCodes.Status400BadRequest,
detail: "payloadDigest is required.");
}
var latest = await hotLookupService
.GetLatestByPayloadDigestAsync(payloadDigest, cancellationToken)
.ConfigureAwait(false);
if (latest is null)
{
return ProblemResultFactory.Create(
context,
ProblemTypes.NotFound,
"No SBOM projection found",
StatusCodes.Status404NotFound,
detail: "No artifact_boms projection row exists for the provided payload digest.");
}
return Results.Ok(latest);
}
private static async Task<IResult> HandleSearchComponentsAsync(
string? purl,
string? name,
string? minVersion,
int limit,
int offset,
ISbomHotLookupService hotLookupService,
HttpContext context,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(hotLookupService);
var hasPurl = !string.IsNullOrWhiteSpace(purl);
var hasName = !string.IsNullOrWhiteSpace(name);
if (!hasPurl && !hasName)
{
return ProblemResultFactory.Create(
context,
ProblemTypes.Validation,
"Invalid component query",
StatusCodes.Status400BadRequest,
detail: "Provide either 'purl' or 'name' query parameter.");
}
if (hasPurl && hasName)
{
return ProblemResultFactory.Create(
context,
ProblemTypes.Validation,
"Ambiguous component query",
StatusCodes.Status400BadRequest,
detail: "Use either 'purl' or 'name', not both.");
}
if (!SbomHotLookupService.IsLimitValid(limit))
{
return ProblemResultFactory.Create(
context,
ProblemTypes.Validation,
"Invalid limit",
StatusCodes.Status400BadRequest,
detail: "limit must be between 1 and 200.");
}
if (!SbomHotLookupService.IsOffsetValid(offset))
{
return ProblemResultFactory.Create(
context,
ProblemTypes.Validation,
"Invalid offset",
StatusCodes.Status400BadRequest,
detail: "offset must be greater than or equal to 0.");
}
var result = await hotLookupService
.SearchComponentsAsync(purl, name, minVersion, limit, offset, cancellationToken)
.ConfigureAwait(false);
return Results.Ok(result);
}
private static async Task<IResult> HandleSearchPendingTriageAsync(
int limit,
int offset,
ISbomHotLookupService hotLookupService,
HttpContext context,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(hotLookupService);
if (!SbomHotLookupService.IsLimitValid(limit))
{
return ProblemResultFactory.Create(
context,
ProblemTypes.Validation,
"Invalid limit",
StatusCodes.Status400BadRequest,
detail: "limit must be between 1 and 200.");
}
if (!SbomHotLookupService.IsOffsetValid(offset))
{
return ProblemResultFactory.Create(
context,
ProblemTypes.Validation,
"Invalid offset",
StatusCodes.Status400BadRequest,
detail: "offset must be greater than or equal to 0.");
}
var result = await hotLookupService
.SearchPendingTriageAsync(limit, offset, cancellationToken)
.ConfigureAwait(false);
return Results.Ok(result);
}
}

View File

@@ -30,6 +30,8 @@ internal static class SbomUploadEndpoints
.Produces(StatusCodes.Status400BadRequest)
.Produces(StatusCodes.Status404NotFound)
.RequireAuthorization(ScannerPolicies.ScansRead);
sbomGroup.MapSbomHotLookupEndpoints();
}
private static async Task<IResult> HandleUploadAsync(