finish off sprint advisories and sprints

This commit is contained in:
master
2026-01-24 00:12:43 +02:00
parent 726d70dc7f
commit c70e83719e
266 changed files with 46699 additions and 1328 deletions

View File

@@ -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;
}
}

View File

@@ -0,0 +1,244 @@
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) 2025 StellaOps
// Sprint: SPRINT_20260122_041_Policy_interop_import_export_rego
// Task: TASK-07 - Platform API 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>
/// Policy import/export interop API endpoints.
/// Provides bidirectional policy exchange between JSON (PolicyPack v2) and OPA/Rego formats.
/// </summary>
public static class PolicyInteropEndpoints
{
/// <summary>
/// Maps policy interop endpoints under /api/v1/policy/interop.
/// </summary>
public static IEndpointRouteBuilder MapPolicyInteropEndpoints(this IEndpointRouteBuilder app)
{
var interop = app.MapGroup("/api/v1/policy/interop")
.WithTags("PolicyInterop");
MapExportEndpoint(interop);
MapImportEndpoint(interop);
MapValidateEndpoint(interop);
MapEvaluateEndpoint(interop);
MapFormatsEndpoint(interop);
return app;
}
private static void MapExportEndpoint(IEndpointRouteBuilder group)
{
// POST /api/v1/policy/interop/export
group.MapPost("/export", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IPolicyInteropService service,
[FromBody] PolicyExportApiRequest request,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.ExportAsync(
requestContext!,
request,
cancellationToken).ConfigureAwait(false);
if (!result.Success)
{
return Results.BadRequest(new { error = "export_failed", diagnostics = result.Diagnostics });
}
return Results.Ok(new PlatformItemResponse<PolicyExportApiResponse>(
requestContext!.TenantId,
requestContext.ActorId,
DateTimeOffset.UtcNow,
false,
0,
result));
})
.WithName("ExportPolicy")
.WithSummary("Export policy to format")
.WithDescription("Exports a PolicyPack v2 document to JSON or OPA/Rego format with optional environment-specific thresholds and remediation hints.")
.RequireAuthorization(PlatformPolicies.PolicyRead);
// POST /api/v1/policy/interop/import
}
private static void MapImportEndpoint(IEndpointRouteBuilder group)
{
group.MapPost("/import", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IPolicyInteropService service,
[FromBody] PolicyImportApiRequest request,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.ImportAsync(
requestContext!,
request,
cancellationToken).ConfigureAwait(false);
if (!result.Success)
{
return Results.BadRequest(new { error = "import_failed", diagnostics = result.Diagnostics });
}
return Results.Ok(new PlatformItemResponse<PolicyImportApiResponse>(
requestContext!.TenantId,
requestContext.ActorId,
DateTimeOffset.UtcNow,
false,
0,
result));
})
.WithName("ImportPolicy")
.WithSummary("Import policy from format")
.WithDescription("Imports a policy from JSON or OPA/Rego format into the native PolicyPack v2 model. Unknown Rego patterns are preserved for OPA evaluation.")
.RequireAuthorization(PlatformPolicies.PolicyWrite);
}
private static void MapValidateEndpoint(IEndpointRouteBuilder group)
{
// POST /api/v1/policy/interop/validate
group.MapPost("/validate", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IPolicyInteropService service,
[FromBody] PolicyValidateApiRequest request,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.ValidateAsync(
requestContext!,
request,
cancellationToken).ConfigureAwait(false);
return Results.Ok(new PlatformItemResponse<PolicyValidateApiResponse>(
requestContext!.TenantId,
requestContext.ActorId,
DateTimeOffset.UtcNow,
false,
0,
result));
})
.WithName("ValidatePolicy")
.WithSummary("Validate policy document")
.WithDescription("Validates a policy document against the PolicyPack v2 schema or checks Rego syntax via embedded OPA.")
.RequireAuthorization(PlatformPolicies.PolicyRead);
}
private static void MapEvaluateEndpoint(IEndpointRouteBuilder group)
{
// POST /api/v1/policy/interop/evaluate
group.MapPost("/evaluate", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IPolicyInteropService service,
[FromBody] PolicyEvaluateApiRequest request,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.EvaluateAsync(
requestContext!,
request,
cancellationToken).ConfigureAwait(false);
var statusCode = result.Decision switch
{
"allow" => StatusCodes.Status200OK,
"warn" => StatusCodes.Status200OK,
"block" => StatusCodes.Status200OK,
_ => StatusCodes.Status200OK
};
return Results.Ok(new PlatformItemResponse<PolicyEvaluateApiResponse>(
requestContext!.TenantId,
requestContext.ActorId,
DateTimeOffset.UtcNow,
false,
0,
result));
})
.WithName("EvaluatePolicy")
.WithSummary("Evaluate policy against input")
.WithDescription("Evaluates a policy (JSON or Rego) against evidence input and returns allow/warn/block decision with remediation hints.")
.RequireAuthorization(PlatformPolicies.PolicyEvaluate);
}
private static void MapFormatsEndpoint(IEndpointRouteBuilder group)
{
// GET /api/v1/policy/interop/formats
group.MapGet("/formats", (
HttpContext context,
PlatformRequestContextResolver resolver) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var formats = new PolicyFormatsApiResponse
{
Formats =
[
new PolicyFormatInfo("json", "PolicyPack v2 (JSON)", "policy.stellaops.io/v2", true, true),
new PolicyFormatInfo("rego", "OPA/Rego", "package stella.release", true, true)
]
};
return Results.Ok(new PlatformItemResponse<PolicyFormatsApiResponse>(
requestContext!.TenantId,
requestContext.ActorId,
DateTimeOffset.UtcNow,
true,
3600,
formats));
})
.WithName("ListPolicyFormats")
.WithSummary("List supported policy formats")
.WithDescription("Returns the list of supported policy import/export formats.")
.RequireAuthorization(PlatformPolicies.PolicyRead);
}
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;
}
}

View File

@@ -0,0 +1,355 @@
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) 2025 StellaOps
// Sprint: SPRINT_20260122_037_Signals_unified_trust_score_algebra
// Task: TSF-005 - Platform API Endpoints (Score Evaluate)
// Task: TSF-011 - Score Replay & Verification Endpoint
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>
/// Score evaluation API endpoints.
/// </summary>
public static class ScoreEndpoints
{
/// <summary>
/// Maps score-related endpoints.
/// </summary>
public static IEndpointRouteBuilder MapScoreEndpoints(this IEndpointRouteBuilder app)
{
var score = app.MapGroup("/api/v1/score")
.WithTags("Score");
MapEvaluateEndpoints(score);
MapHistoryEndpoints(score);
MapWeightsEndpoints(score);
MapReplayEndpoints(score);
return app;
}
private static void MapHistoryEndpoints(IEndpointRouteBuilder score)
{
// GET /api/v1/score/history - Get score history
score.MapGet("/history", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IScoreEvaluationService service,
[FromQuery] string cve_id,
[FromQuery] string? purl,
[FromQuery] int? limit,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
if (string.IsNullOrWhiteSpace(cve_id))
{
return Results.BadRequest(new { error = "cve_id query parameter is required" });
}
var result = await service.GetHistoryAsync(
requestContext!,
cve_id,
purl,
limit ?? 50,
cancellationToken).ConfigureAwait(false);
return Results.Ok(new PlatformListResponse<Contracts.ScoreHistoryRecord>(
requestContext!.TenantId,
requestContext.ActorId,
result.DataAsOf,
result.Cached,
result.CacheTtlSeconds,
result.Value,
result.Value.Count));
})
.WithName("GetScoreHistory")
.WithSummary("Get score history")
.WithDescription("Retrieves score computation history for a CVE, optionally filtered by purl.")
.RequireAuthorization(PlatformPolicies.ScoreRead);
}
private static void MapEvaluateEndpoints(IEndpointRouteBuilder score)
{
// POST /api/v1/score/evaluate - Compute unified score
score.MapPost("/evaluate", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IScoreEvaluationService service,
[FromBody] ScoreEvaluateRequest request,
[FromQuery] bool? include_delta,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
// Override options from query params if provided
var effectiveOptions = request.Options ?? new ScoreEvaluateOptions();
if (include_delta.HasValue)
{
effectiveOptions = effectiveOptions with { IncludeDelta = include_delta.Value };
}
var effectiveRequest = request with { Options = effectiveOptions };
var result = await service.EvaluateAsync(
requestContext!,
effectiveRequest,
cancellationToken).ConfigureAwait(false);
return Results.Ok(new PlatformItemResponse<ScoreEvaluateResponse>(
requestContext!.TenantId,
requestContext.ActorId,
result.DataAsOf,
result.Cached,
result.CacheTtlSeconds,
result.Value));
})
.WithName("EvaluateScore")
.WithSummary("Compute unified score")
.WithDescription("Evaluates a unified trust score combining EWS computation with Determinization entropy.")
.RequireAuthorization(PlatformPolicies.ScoreEvaluate);
// GET /api/v1/score/{scoreId} - Get score by ID
score.MapGet("/{scoreId}", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IScoreEvaluationService service,
string scoreId,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.GetByIdAsync(
requestContext!,
scoreId,
cancellationToken).ConfigureAwait(false);
if (result.Value is null)
{
return Results.NotFound(new { error = "Score not found", score_id = scoreId });
}
return Results.Ok(new PlatformItemResponse<ScoreEvaluateResponse>(
requestContext!.TenantId,
requestContext.ActorId,
result.DataAsOf,
result.Cached,
result.CacheTtlSeconds,
result.Value));
})
.WithName("GetScore")
.WithSummary("Get score by ID")
.WithDescription("Retrieves a previously computed score by its unique identifier.")
.RequireAuthorization(PlatformPolicies.ScoreRead);
}
private static void MapWeightsEndpoints(IEndpointRouteBuilder score)
{
var weights = score.MapGroup("/weights").WithTags("Score Weights");
// GET /api/v1/score/weights - List available weight manifests
weights.MapGet("/", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IScoreEvaluationService service,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.ListWeightManifestsAsync(
requestContext!,
cancellationToken).ConfigureAwait(false);
return Results.Ok(new PlatformListResponse<WeightManifestSummary>(
requestContext!.TenantId,
requestContext.ActorId,
result.DataAsOf,
result.Cached,
result.CacheTtlSeconds,
result.Value,
result.Value.Count));
})
.WithName("ListWeightManifests")
.WithSummary("List weight manifests")
.WithDescription("Lists all available EWS weight manifests.")
.RequireAuthorization(PlatformPolicies.ScoreRead);
// GET /api/v1/score/weights/{version} - Get specific manifest
weights.MapGet("/{version}", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IScoreEvaluationService service,
string version,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.GetWeightManifestAsync(
requestContext!,
version,
cancellationToken).ConfigureAwait(false);
if (result.Value is null)
{
return Results.NotFound(new { error = "Weight manifest not found", version });
}
return Results.Ok(new PlatformItemResponse<WeightManifestDetail>(
requestContext!.TenantId,
requestContext.ActorId,
result.DataAsOf,
result.Cached,
result.CacheTtlSeconds,
result.Value));
})
.WithName("GetWeightManifest")
.WithSummary("Get weight manifest")
.WithDescription("Retrieves a specific EWS weight manifest by version.")
.RequireAuthorization(PlatformPolicies.ScoreRead);
// GET /api/v1/score/weights/effective - Get effective manifest for current date
weights.MapGet("/effective", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IScoreEvaluationService service,
[FromQuery] DateTimeOffset? as_of,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.GetEffectiveWeightManifestAsync(
requestContext!,
as_of ?? DateTimeOffset.UtcNow,
cancellationToken).ConfigureAwait(false);
if (result.Value is null)
{
return Results.NotFound(new { error = "No effective weight manifest found" });
}
return Results.Ok(new PlatformItemResponse<WeightManifestDetail>(
requestContext!.TenantId,
requestContext.ActorId,
result.DataAsOf,
result.Cached,
result.CacheTtlSeconds,
result.Value));
})
.WithName("GetEffectiveWeightManifest")
.WithSummary("Get effective weight manifest")
.WithDescription("Retrieves the effective EWS weight manifest for a given date.")
.RequireAuthorization(PlatformPolicies.ScoreRead);
}
// TSF-011: Replay and verification endpoints
private static void MapReplayEndpoints(IEndpointRouteBuilder score)
{
// GET /api/v1/score/{scoreId}/replay - Fetch signed replay proof
score.MapGet("/{scoreId}/replay", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IScoreEvaluationService service,
string scoreId,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.GetReplayAsync(
requestContext!,
scoreId,
cancellationToken).ConfigureAwait(false);
if (result.Value is null)
{
return Results.NotFound(new { error = "Replay log not found", score_id = scoreId });
}
return Results.Ok(new PlatformItemResponse<ScoreReplayResponse>(
requestContext!.TenantId,
requestContext.ActorId,
result.DataAsOf,
result.Cached,
result.CacheTtlSeconds,
result.Value));
})
.WithName("GetScoreReplay")
.WithSummary("Get score replay proof")
.WithDescription("Retrieves a signed replay log for a previously computed score, enabling independent verification by auditors.")
.RequireAuthorization(PlatformPolicies.ScoreRead);
// POST /api/v1/score/verify - Verify a replay log
score.MapPost("/verify", async Task<IResult> (
HttpContext context,
PlatformRequestContextResolver resolver,
IScoreEvaluationService service,
[FromBody] ScoreVerifyRequest request,
CancellationToken cancellationToken) =>
{
if (!TryResolveContext(context, resolver, out var requestContext, out var failure))
{
return failure!;
}
var result = await service.VerifyReplayAsync(
requestContext!,
request,
cancellationToken).ConfigureAwait(false);
return Results.Ok(new PlatformItemResponse<ScoreVerifyResponse>(
requestContext!.TenantId,
requestContext.ActorId,
result.DataAsOf,
result.Cached,
result.CacheTtlSeconds,
result.Value));
})
.WithName("VerifyScoreReplay")
.WithSummary("Verify score replay")
.WithDescription("Verifies a signed replay log by re-executing the score computation and comparing results.")
.RequireAuthorization(PlatformPolicies.ScoreRead);
}
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;
}
}