save checkpoint
This commit is contained in:
@@ -133,6 +133,8 @@ internal static class SbomEndpoints
|
||||
sbomDocument,
|
||||
format,
|
||||
contentDigest,
|
||||
snapshot.Target.Digest,
|
||||
parsed.Value,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
sbomDocument.Dispose();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user