finish off sprint advisories and sprints
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
// Copyright (c) 2025 StellaOps
|
||||
// Sprint: SPRINT_20260122_039_Scanner_runtime_linkage_verification
|
||||
// Task: RLV-009 - Platform API: Function Map Endpoints
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using StellaOps.Platform.WebService.Constants;
|
||||
using StellaOps.Platform.WebService.Contracts;
|
||||
using StellaOps.Platform.WebService.Services;
|
||||
|
||||
namespace StellaOps.Platform.WebService.Endpoints;
|
||||
|
||||
/// <summary>
|
||||
/// Function map management API endpoints.
|
||||
/// </summary>
|
||||
public static class FunctionMapEndpoints
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps function-map-related endpoints.
|
||||
/// </summary>
|
||||
public static IEndpointRouteBuilder MapFunctionMapEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var maps = app.MapGroup("/api/v1/function-maps")
|
||||
.WithTags("Function Maps");
|
||||
|
||||
MapCrudEndpoints(maps);
|
||||
MapVerifyEndpoints(maps);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
private static void MapCrudEndpoints(IEndpointRouteBuilder maps)
|
||||
{
|
||||
// POST /api/v1/function-maps - Create function map
|
||||
maps.MapPost("/", async Task<IResult> (
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
IFunctionMapService service,
|
||||
[FromBody] CreateFunctionMapRequest request,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var result = await service.CreateAsync(
|
||||
requestContext!,
|
||||
request,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Created(
|
||||
$"/api/v1/function-maps/{result.Value.Id}",
|
||||
new PlatformItemResponse<FunctionMapDetail>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
result.DataAsOf,
|
||||
result.Cached,
|
||||
result.CacheTtlSeconds,
|
||||
result.Value));
|
||||
})
|
||||
.WithName("CreateFunctionMap")
|
||||
.WithSummary("Create function map")
|
||||
.WithDescription("Creates a new function map from an SBOM reference and hot function patterns.")
|
||||
.RequireAuthorization(PlatformPolicies.FunctionMapWrite);
|
||||
|
||||
// GET /api/v1/function-maps - List function maps
|
||||
maps.MapGet("/", async Task<IResult> (
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
IFunctionMapService service,
|
||||
[FromQuery] int? limit,
|
||||
[FromQuery] int? offset,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var result = await service.ListAsync(
|
||||
requestContext!,
|
||||
limit ?? 100,
|
||||
offset ?? 0,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Ok(new PlatformListResponse<FunctionMapSummary>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
result.DataAsOf,
|
||||
result.Cached,
|
||||
result.CacheTtlSeconds,
|
||||
result.Value,
|
||||
result.Value.Count,
|
||||
limit ?? 100,
|
||||
offset ?? 0));
|
||||
})
|
||||
.WithName("ListFunctionMaps")
|
||||
.WithSummary("List function maps")
|
||||
.WithDescription("Lists all function maps for the current tenant.")
|
||||
.RequireAuthorization(PlatformPolicies.FunctionMapRead);
|
||||
|
||||
// GET /api/v1/function-maps/{id} - Get function map by ID
|
||||
maps.MapGet("/{id}", async Task<IResult> (
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
IFunctionMapService service,
|
||||
string id,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var result = await service.GetByIdAsync(
|
||||
requestContext!,
|
||||
id,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (result.Value is null)
|
||||
{
|
||||
return Results.NotFound(new { error = "Function map not found", id });
|
||||
}
|
||||
|
||||
return Results.Ok(new PlatformItemResponse<FunctionMapDetail>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
result.DataAsOf,
|
||||
result.Cached,
|
||||
result.CacheTtlSeconds,
|
||||
result.Value));
|
||||
})
|
||||
.WithName("GetFunctionMap")
|
||||
.WithSummary("Get function map")
|
||||
.WithDescription("Retrieves a function map by its unique identifier.")
|
||||
.RequireAuthorization(PlatformPolicies.FunctionMapRead);
|
||||
|
||||
// DELETE /api/v1/function-maps/{id} - Delete function map
|
||||
maps.MapDelete("/{id}", async Task<IResult> (
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
IFunctionMapService service,
|
||||
string id,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var result = await service.DeleteAsync(
|
||||
requestContext!,
|
||||
id,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!result.Value)
|
||||
{
|
||||
return Results.NotFound(new { error = "Function map not found", id });
|
||||
}
|
||||
|
||||
return Results.NoContent();
|
||||
})
|
||||
.WithName("DeleteFunctionMap")
|
||||
.WithSummary("Delete function map")
|
||||
.WithDescription("Deletes a function map by its unique identifier.")
|
||||
.RequireAuthorization(PlatformPolicies.FunctionMapWrite);
|
||||
}
|
||||
|
||||
private static void MapVerifyEndpoints(IEndpointRouteBuilder maps)
|
||||
{
|
||||
// POST /api/v1/function-maps/{id}/verify - Verify observations against map
|
||||
maps.MapPost("/{id}/verify", async Task<IResult> (
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
IFunctionMapService service,
|
||||
string id,
|
||||
[FromBody] VerifyFunctionMapRequest request,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var result = await service.VerifyAsync(
|
||||
requestContext!,
|
||||
id,
|
||||
request,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Ok(new PlatformItemResponse<FunctionMapVerifyResponse>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
result.DataAsOf,
|
||||
result.Cached,
|
||||
result.CacheTtlSeconds,
|
||||
result.Value));
|
||||
})
|
||||
.WithName("VerifyFunctionMap")
|
||||
.WithSummary("Verify function map")
|
||||
.WithDescription("Verifies runtime observations against a declared function map.")
|
||||
.RequireAuthorization(PlatformPolicies.FunctionMapVerify);
|
||||
|
||||
// GET /api/v1/function-maps/{id}/coverage - Get coverage statistics
|
||||
maps.MapGet("/{id}/coverage", async Task<IResult> (
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
IFunctionMapService service,
|
||||
string id,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
|
||||
{
|
||||
return failure!;
|
||||
}
|
||||
|
||||
var result = await service.GetCoverageAsync(
|
||||
requestContext!,
|
||||
id,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Ok(new PlatformItemResponse<FunctionMapCoverageResponse>(
|
||||
requestContext!.TenantId,
|
||||
requestContext.ActorId,
|
||||
result.DataAsOf,
|
||||
result.Cached,
|
||||
result.CacheTtlSeconds,
|
||||
result.Value));
|
||||
})
|
||||
.WithName("GetFunctionMapCoverage")
|
||||
.WithSummary("Get function map coverage")
|
||||
.WithDescription("Returns current coverage statistics for a function map.")
|
||||
.RequireAuthorization(PlatformPolicies.FunctionMapRead);
|
||||
}
|
||||
|
||||
private static bool TryResolveContext(
|
||||
HttpContext context,
|
||||
PlatformRequestContextResolver resolver,
|
||||
out PlatformRequestContext? requestContext,
|
||||
out IResult? failure)
|
||||
{
|
||||
if (resolver.TryResolve(context, out requestContext, out var error))
|
||||
{
|
||||
failure = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
failure = Results.BadRequest(new { error = error ?? "tenant_missing" });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user