Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Scanner.WebService.Contracts;
|
||||
using StellaOps.Scanner.WebService.Services;
|
||||
|
||||
namespace StellaOps.Scanner.WebService.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/v1/findings")]
|
||||
[Produces("application/json")]
|
||||
public sealed class FindingsEvidenceController : ControllerBase
|
||||
{
|
||||
private readonly IEvidenceCompositionService _evidenceService;
|
||||
private readonly ITriageQueryService _triageService;
|
||||
private readonly ILogger<FindingsEvidenceController> _logger;
|
||||
|
||||
public FindingsEvidenceController(
|
||||
IEvidenceCompositionService evidenceService,
|
||||
ITriageQueryService triageService,
|
||||
ILogger<FindingsEvidenceController> logger)
|
||||
{
|
||||
_evidenceService = evidenceService ?? throw new ArgumentNullException(nameof(evidenceService));
|
||||
_triageService = triageService ?? throw new ArgumentNullException(nameof(triageService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get consolidated evidence for a finding.
|
||||
/// </summary>
|
||||
/// <param name="findingId">The finding identifier.</param>
|
||||
/// <param name="includeRaw">Include raw source locations (requires elevated permissions).</param>
|
||||
/// <response code="200">Evidence retrieved successfully.</response>
|
||||
/// <response code="404">Finding not found.</response>
|
||||
/// <response code="403">Insufficient permissions for raw source.</response>
|
||||
[HttpGet("{findingId}/evidence")]
|
||||
[ProducesResponseType(typeof(FindingEvidenceResponse), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> GetEvidenceAsync(
|
||||
[FromRoute] string findingId,
|
||||
[FromQuery] bool includeRaw = false,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
_logger.LogDebug("Getting evidence for finding {FindingId}", findingId);
|
||||
|
||||
if (includeRaw && !User.HasClaim("scope", "evidence:raw"))
|
||||
{
|
||||
return Forbid("Requires evidence:raw scope for raw source access");
|
||||
}
|
||||
|
||||
var finding = await _triageService.GetFindingAsync(findingId, ct).ConfigureAwait(false);
|
||||
if (finding is null)
|
||||
{
|
||||
return NotFound(new { error = "Finding not found", findingId });
|
||||
}
|
||||
|
||||
var response = await _evidenceService.ComposeAsync(finding, includeRaw, ct).ConfigureAwait(false);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get evidence for multiple findings (batch).
|
||||
/// </summary>
|
||||
[HttpPost("evidence/batch")]
|
||||
[ProducesResponseType(typeof(BatchEvidenceResponse), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetBatchEvidenceAsync(
|
||||
[FromBody] BatchEvidenceRequest request,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
if (request.FindingIds.Count > 100)
|
||||
{
|
||||
return BadRequest(new { error = "Maximum 100 findings per batch" });
|
||||
}
|
||||
|
||||
var results = new List<FindingEvidenceResponse>();
|
||||
foreach (var findingId in request.FindingIds)
|
||||
{
|
||||
var finding = await _triageService.GetFindingAsync(findingId, ct).ConfigureAwait(false);
|
||||
if (finding is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var evidence = await _evidenceService.ComposeAsync(finding, includeRaw: false, ct).ConfigureAwait(false);
|
||||
results.Add(evidence);
|
||||
}
|
||||
|
||||
return Ok(new BatchEvidenceResponse { Findings = results });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user