Refactor code structure for improved readability and maintainability; optimize performance in key functions.

This commit is contained in:
master
2025-12-22 19:06:31 +02:00
parent dfaa2079aa
commit 4602ccc3a3
1444 changed files with 109919 additions and 8058 deletions

View File

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