feat: complete task board workflow gates
This commit is contained in:
@@ -10,7 +10,7 @@ namespace Nexus.Api.Controllers;
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("api/v1/tasks")]
|
||||
public class TasksController(ITaskService taskService, IAgentService agentService) : ControllerBase
|
||||
public class TasksController(ITaskService taskService, IAgentService agentService, IConfiguration configuration) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IResult> GetAll(CancellationToken ct)
|
||||
@@ -117,12 +117,12 @@ public class TasksController(ITaskService taskService, IAgentService agentServic
|
||||
/// X-Nexus-Api-Key / JWT. Kein [AllowAnonymous] mehr.
|
||||
/// Für Agent-zu-Agent-Kommunikation den /api/bridge/board Endpunkt nutzen.
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[HttpGet("board")]
|
||||
public async Task<IResult> GetBoard(CancellationToken ct)
|
||||
{
|
||||
// Erfordert mindestens einen identifizierbaren Agent-Aufrufer
|
||||
var agentHeader = await GetAllowedAgentHeaderAsync(ct);
|
||||
var isApiKey = HttpContext.User.IsInRole("Service");
|
||||
var agentHeader = await RequestAuthorizationHelper.ResolveAllowedAgentHeaderAsync(HttpContext, agentService, ct);
|
||||
var isApiKey = RequestAuthorizationHelper.IsAuthenticatedService(HttpContext, configuration);
|
||||
var isAuth = HttpContext.User.Identity?.IsAuthenticated == true;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(agentHeader) && !isApiKey && !isAuth)
|
||||
@@ -136,33 +136,28 @@ public class TasksController(ITaskService taskService, IAgentService agentServic
|
||||
/// Wird vom Iris Autonomous Worker genutzt.
|
||||
///
|
||||
/// SICHERHEIT: Erfordert X-Agent-Id Header (nur iris) ODER
|
||||
/// X-Nexus-Api-Key / JWT-authenticated user.
|
||||
/// X-Nexus-Api-Key / Service-Principal ODER owner/admin JWT.
|
||||
/// Für Agent-zu-Agent-Kommunikation den /api/bridge Endpunkt nutzen.
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("reset-stale")]
|
||||
public async Task<IResult> ResetStale([FromBody] ResetStaleRequest request, CancellationToken ct)
|
||||
{
|
||||
var agentHeader = await GetAllowedAgentHeaderAsync(ct);
|
||||
var isApiKey = HttpContext.User.IsInRole("Service");
|
||||
var isAuth = HttpContext.User.Identity?.IsAuthenticated == true;
|
||||
var agentHeaderResolution = await RequestAuthorizationHelper.ResolveAgentHeaderAsync(HttpContext, agentService, ct);
|
||||
var isService = RequestAuthorizationHelper.IsAuthenticatedService(HttpContext, configuration);
|
||||
var isPrivilegedUser = RequestAuthorizationHelper.IsPrivilegedUser(HttpContext);
|
||||
|
||||
var isIris = string.Equals(agentHeaderResolution.AgentId, "iris", StringComparison.OrdinalIgnoreCase);
|
||||
if (!isIris && !isService && !isPrivilegedUser)
|
||||
{
|
||||
// A presented but unrecognized agent header is an invalid credential, not a missing one.
|
||||
if (HttpContext.User.Identity?.IsAuthenticated == true || agentHeaderResolution.HeaderProvided)
|
||||
return Results.Forbid();
|
||||
|
||||
// Nur iris, nexus-system (ApiKey) oder JWT-authenticated user
|
||||
var isIris = string.Equals(agentHeader, "iris", StringComparison.OrdinalIgnoreCase);
|
||||
if (!isIris && !isApiKey && !isAuth)
|
||||
return Results.Unauthorized();
|
||||
}
|
||||
|
||||
var count = await taskService.ResetStaleAsync(request.StaleHours, ct);
|
||||
return Results.Ok(new ResetStaleResponse(count));
|
||||
}
|
||||
|
||||
private async Task<string?> GetAllowedAgentHeaderAsync(CancellationToken ct)
|
||||
{
|
||||
var headerValue = HttpContext.Request.Headers["X-Agent-Id"].FirstOrDefault();
|
||||
if (string.IsNullOrWhiteSpace(headerValue))
|
||||
return null;
|
||||
|
||||
var normalized = headerValue.Trim().ToLowerInvariant();
|
||||
var allowed = await agentService.GetAllowedAgentIdsAsync(ct);
|
||||
return allowed.Contains(normalized) ? normalized : null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user