- Added IIssuerDirectory interface for managing VEX document issuers, including methods for registration, revocation, and trust validation. - Created InMemoryIssuerDirectory class as an in-memory implementation of IIssuerDirectory for testing and single-instance deployments. - Introduced ISignatureVerifier interface for verifying signatures on VEX documents, with support for multiple signature formats. - Developed SignatureVerifier class as the default implementation of ISignatureVerifier, allowing extensibility for different signature formats. - Implemented handlers for DSSE and JWS signature formats, including methods for verification and signature extraction. - Defined various records and enums for issuer and signature metadata, enhancing the structure and clarity of the verification process.
126 lines
4.6 KiB
C#
126 lines
4.6 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using StellaOps.Auth.Abstractions;
|
|
using StellaOps.Policy.Engine.ConsoleSurface;
|
|
using StellaOps.Policy.Engine.Options;
|
|
|
|
namespace StellaOps.Policy.Engine.Endpoints;
|
|
|
|
/// <summary>
|
|
/// Console endpoints for attestation reports per CONTRACT-VERIFICATION-POLICY-006.
|
|
/// </summary>
|
|
internal static class ConsoleAttestationReportEndpoints
|
|
{
|
|
public static IEndpointRouteBuilder MapConsoleAttestationReports(this IEndpointRouteBuilder routes)
|
|
{
|
|
var group = routes.MapGroup("/policy/console/attestation")
|
|
.WithTags("Console Attestation Reports")
|
|
.RequireRateLimiting(PolicyEngineRateLimitOptions.PolicyName);
|
|
|
|
group.MapPost("/reports", QueryReportsAsync)
|
|
.WithName("PolicyEngine.ConsoleAttestationReports")
|
|
.WithSummary("Query attestation reports for Console")
|
|
.RequireAuthorization(policy => policy.RequireClaim("scope", StellaOpsScopes.PolicyRead))
|
|
.Produces<ConsoleAttestationReportResponse>(StatusCodes.Status200OK)
|
|
.ProducesValidationProblem();
|
|
|
|
group.MapPost("/dashboard", GetDashboardAsync)
|
|
.WithName("PolicyEngine.ConsoleAttestationDashboard")
|
|
.WithSummary("Get attestation dashboard for Console")
|
|
.RequireAuthorization(policy => policy.RequireClaim("scope", StellaOpsScopes.PolicyRead))
|
|
.Produces<ConsoleAttestationDashboardResponse>(StatusCodes.Status200OK)
|
|
.ProducesValidationProblem();
|
|
|
|
group.MapGet("/report/{artifactDigest}", GetReportAsync)
|
|
.WithName("PolicyEngine.ConsoleGetAttestationReport")
|
|
.WithSummary("Get attestation report for a specific artifact")
|
|
.RequireAuthorization(policy => policy.RequireClaim("scope", StellaOpsScopes.PolicyRead))
|
|
.Produces<ConsoleArtifactReport>(StatusCodes.Status200OK)
|
|
.Produces(StatusCodes.Status404NotFound);
|
|
|
|
return routes;
|
|
}
|
|
|
|
private static async Task<IResult> QueryReportsAsync(
|
|
[FromBody] ConsoleAttestationReportRequest? request,
|
|
ConsoleAttestationReportService service,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (request is null)
|
|
{
|
|
return Results.ValidationProblem(new Dictionary<string, string[]>
|
|
{
|
|
["request"] = ["Request body is required."]
|
|
});
|
|
}
|
|
|
|
if (request.Page < 1)
|
|
{
|
|
return Results.ValidationProblem(new Dictionary<string, string[]>
|
|
{
|
|
["page"] = ["Page must be at least 1."]
|
|
});
|
|
}
|
|
|
|
if (request.PageSize < 1 || request.PageSize > 100)
|
|
{
|
|
return Results.ValidationProblem(new Dictionary<string, string[]>
|
|
{
|
|
["pageSize"] = ["Page size must be between 1 and 100."]
|
|
});
|
|
}
|
|
|
|
var response = await service.QueryReportsAsync(request, cancellationToken).ConfigureAwait(false);
|
|
return Results.Json(response);
|
|
}
|
|
|
|
private static async Task<IResult> GetDashboardAsync(
|
|
[FromBody] ConsoleAttestationDashboardRequest? request,
|
|
ConsoleAttestationReportService service,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var effectiveRequest = request ?? new ConsoleAttestationDashboardRequest(
|
|
TimeRange: "24h",
|
|
PolicyIds: null,
|
|
ArtifactUriPattern: null);
|
|
|
|
var response = await service.GetDashboardAsync(effectiveRequest, cancellationToken).ConfigureAwait(false);
|
|
return Results.Json(response);
|
|
}
|
|
|
|
private static async Task<IResult> GetReportAsync(
|
|
[FromRoute] string artifactDigest,
|
|
ConsoleAttestationReportService service,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(artifactDigest))
|
|
{
|
|
return Results.ValidationProblem(new Dictionary<string, string[]>
|
|
{
|
|
["artifactDigest"] = ["Artifact digest is required."]
|
|
});
|
|
}
|
|
|
|
var request = new ConsoleAttestationReportRequest(
|
|
ArtifactDigests: [artifactDigest],
|
|
ArtifactUriPattern: null,
|
|
PolicyIds: null,
|
|
PredicateTypes: null,
|
|
StatusFilter: null,
|
|
FromTime: null,
|
|
ToTime: null,
|
|
GroupBy: null,
|
|
SortBy: null,
|
|
Page: 1,
|
|
PageSize: 1);
|
|
|
|
var response = await service.QueryReportsAsync(request, cancellationToken).ConfigureAwait(false);
|
|
|
|
if (response.Reports.Count == 0)
|
|
{
|
|
return Results.NotFound();
|
|
}
|
|
|
|
return Results.Json(response.Reports[0]);
|
|
}
|
|
}
|