Files
git.stella-ops.org/src/Policy/StellaOps.Policy.Engine/Endpoints/ConsoleAttestationReportEndpoints.cs
StellaOps Bot 5e514532df Implement VEX document verification system with issuer management and signature verification
- 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.
2025-12-06 13:41:22 +02:00

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]);
}
}