wip: doctor/cli/docs/api to vector db consolidation; api hardening for descriptions, tenant, and scopes; migrations and conversions of all DALs to EF v10
This commit is contained in:
@@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using StellaOps.AdvisoryAI.Runs;
|
||||
using StellaOps.AdvisoryAI.WebService.Security;
|
||||
using StellaOps.Determinism;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
@@ -27,64 +28,82 @@ public static class RunEndpoints
|
||||
public static RouteGroupBuilder MapRunEndpoints(this IEndpointRouteBuilder builder)
|
||||
{
|
||||
var group = builder.MapGroup("/api/v1/runs")
|
||||
.WithTags("Runs");
|
||||
.WithTags("Runs")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.ViewPolicy);
|
||||
|
||||
group.MapPost("/", CreateRunAsync)
|
||||
.WithName("CreateRun")
|
||||
.WithSummary("Creates a new AI investigation run")
|
||||
.WithDescription("Creates a new AI investigation run scoped to the authenticated tenant, capturing the title, objective, and optional CVE/component/SBOM context. The run begins in the Created state and accumulates events as the investigation progresses. Returns 201 with the initial run state and a Location header.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunDto>(StatusCodes.Status201Created)
|
||||
.ProducesValidationProblem();
|
||||
|
||||
group.MapGet("/{runId}", GetRunAsync)
|
||||
.WithName("GetRun")
|
||||
.WithSummary("Gets a run by ID")
|
||||
.WithDescription("Returns the current state of an AI investigation run, including status, event count, artifact count, content digest, attestation flag, context, and approval info. Returns 404 if the run does not exist or belongs to a different tenant.")
|
||||
.Produces<RunDto>()
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapGet("/", QueryRunsAsync)
|
||||
.WithName("QueryRuns")
|
||||
.WithSummary("Queries runs with filters")
|
||||
.WithDescription("Returns a paginated list of AI investigation runs for the current tenant, optionally filtered by initiator, CVE ID, component, and status. Supports skip/take pagination. Results are ordered by creation time descending.")
|
||||
.Produces<RunQueryResultDto>();
|
||||
|
||||
group.MapGet("/{runId}/timeline", GetTimelineAsync)
|
||||
.WithName("GetRunTimeline")
|
||||
.WithSummary("Gets the event timeline for a run")
|
||||
.WithDescription("Returns the ordered event timeline for an AI investigation run, including user turns, assistant turns, proposed actions, approvals, and artifact additions. Supports skip/take pagination over the event sequence. Returns 404 if the run does not exist.")
|
||||
.Produces<ImmutableArray<RunEventDto>>()
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapPost("/{runId}/events", AddEventAsync)
|
||||
.WithName("AddRunEvent")
|
||||
.WithSummary("Adds an event to a run")
|
||||
.WithDescription("Appends a typed event to an active AI investigation run, supporting arbitrary event types with optional content payload, evidence links, and parent event reference for threading. Returns 201 with the created event. Returns 404 if the run does not exist or is in a terminal state.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunEventDto>(StatusCodes.Status201Created)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapPost("/{runId}/turns/user", AddUserTurnAsync)
|
||||
.WithName("AddUserTurn")
|
||||
.WithSummary("Adds a user turn to the run")
|
||||
.WithDescription("Appends a user conversational turn to an active AI investigation run, recording the message text, actor ID, and optional evidence links. User turns drive the investigation dialogue and are included in the run content digest for attestation purposes.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunEventDto>(StatusCodes.Status201Created)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapPost("/{runId}/turns/assistant", AddAssistantTurnAsync)
|
||||
.WithName("AddAssistantTurn")
|
||||
.WithSummary("Adds an assistant turn to the run")
|
||||
.WithDescription("Appends an AI assistant conversational turn to an active run, recording the generated message and optional evidence links. Assistant turns are included in the run content digest and contribute to the attestable evidence chain for the investigation.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunEventDto>(StatusCodes.Status201Created)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapPost("/{runId}/actions", ProposeActionAsync)
|
||||
.WithName("ProposeAction")
|
||||
.WithSummary("Proposes an action in the run")
|
||||
.WithDescription("Records an AI-proposed action in a run, including the action type, subject, rationale, parameters, and whether human approval is required before execution. Actions flagged as requiring approval transition the run to PendingApproval once approval is requested. Returns 404 if the run is not active.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunEventDto>(StatusCodes.Status201Created)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapPost("/{runId}/approval/request", RequestApprovalAsync)
|
||||
.WithName("RequestApproval")
|
||||
.WithSummary("Requests approval for pending actions")
|
||||
.WithDescription("Transitions a run to the PendingApproval state and notifies the designated approvers. The request body specifies the approver IDs and an optional reason. Returns the updated run state. Returns 404 if the run does not exist or is not in a state that allows approval requests.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunDto>()
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapPost("/{runId}/approval/decide", ApproveAsync)
|
||||
.WithName("ApproveRun")
|
||||
.WithSummary("Approves or rejects a run")
|
||||
.WithDescription("Records an approval or rejection decision for a run in PendingApproval state. On approval, the run transitions back to Active so approved actions can be executed. On rejection, the run is cancelled. Returns 400 if the run is not in an approvable state.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunDto>()
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status400BadRequest);
|
||||
@@ -92,6 +111,8 @@ public static class RunEndpoints
|
||||
group.MapPost("/{runId}/actions/{actionEventId}/execute", ExecuteActionAsync)
|
||||
.WithName("ExecuteAction")
|
||||
.WithSummary("Executes an approved action")
|
||||
.WithDescription("Marks a previously proposed and approved action as executed, recording the execution result in the run timeline. Only actions that have been approved may be executed; attempting to execute a pending or rejected action returns 400. Returns 404 if the run or action event does not exist.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunEventDto>()
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status400BadRequest);
|
||||
@@ -99,12 +120,16 @@ public static class RunEndpoints
|
||||
group.MapPost("/{runId}/artifacts", AddArtifactAsync)
|
||||
.WithName("AddArtifact")
|
||||
.WithSummary("Adds an artifact to the run")
|
||||
.WithDescription("Attaches an artifact (evidence pack, report, SBOM snippet, or other typed asset) to an active run. The artifact is recorded with its content digest, media type, size, and optional inline content. Adding an artifact updates the run's content digest, contributing to its attestation chain.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunDto>()
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapPost("/{runId}/complete", CompleteRunAsync)
|
||||
.WithName("CompleteRun")
|
||||
.WithSummary("Completes a run")
|
||||
.WithDescription("Transitions an active AI investigation run to the Completed terminal state, optionally recording a summary of findings. Once completed, the run is immutable and ready for attestation. Returns 400 if the run is already in a terminal state.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunDto>()
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status400BadRequest);
|
||||
@@ -112,6 +137,8 @@ public static class RunEndpoints
|
||||
group.MapPost("/{runId}/cancel", CancelRunAsync)
|
||||
.WithName("CancelRun")
|
||||
.WithSummary("Cancels a run")
|
||||
.WithDescription("Transitions an active or pending-approval AI investigation run to the Cancelled terminal state, optionally recording a cancellation reason. Cancelled runs are immutable and excluded from active and pending-approval queries. Returns 400 if the run is already in a terminal state.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunDto>()
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status400BadRequest);
|
||||
@@ -119,12 +146,16 @@ public static class RunEndpoints
|
||||
group.MapPost("/{runId}/handoff", HandOffRunAsync)
|
||||
.WithName("HandOffRun")
|
||||
.WithSummary("Hands off a run to another user")
|
||||
.WithDescription("Transfers ownership of an active AI investigation run to another user within the same tenant. A hand-off event is recorded in the run timeline with the target user ID and an optional message. Returns 404 if the run does not exist or the target user is not valid.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunDto>()
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapPost("/{runId}/attest", AttestRunAsync)
|
||||
.WithName("AttestRun")
|
||||
.WithSummary("Creates an attestation for a completed run")
|
||||
.WithDescription("Generates and persists a cryptographic attestation for a completed AI investigation run, recording the content digest, model metadata, and claim hashes. The attestation can optionally be signed via the attestation sign endpoint. Returns 400 if the run is not in a terminal state or has already been attested.")
|
||||
.RequireAuthorization(AdvisoryAIPolicies.OperatePolicy)
|
||||
.Produces<RunDto>()
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.Produces(StatusCodes.Status400BadRequest);
|
||||
@@ -132,11 +163,13 @@ public static class RunEndpoints
|
||||
group.MapGet("/active", GetActiveRunsAsync)
|
||||
.WithName("GetActiveRuns")
|
||||
.WithSummary("Gets active runs for the current user")
|
||||
.WithDescription("Returns up to 50 AI investigation runs in Created, Active, or PendingApproval state that were initiated by the current user within the authenticated tenant. Use this endpoint to resume in-progress investigations or surface runs awaiting user input.")
|
||||
.Produces<ImmutableArray<RunDto>>();
|
||||
|
||||
group.MapGet("/pending-approval", GetPendingApprovalAsync)
|
||||
.WithName("GetPendingApproval")
|
||||
.WithSummary("Gets runs pending approval")
|
||||
.WithDescription("Returns up to 50 AI investigation runs in the PendingApproval state for the authenticated tenant. Use this endpoint to surface runs that are blocked on a human approval decision before their proposed actions can be executed.")
|
||||
.Produces<ImmutableArray<RunDto>>();
|
||||
|
||||
return group;
|
||||
|
||||
Reference in New Issue
Block a user