Files
git.stella-ops.org/src/Scheduler/StellaOps.Scheduler.WebService/VulnerabilityResolverJobs/ResolverJobEndpointExtensions.cs
master 8355e2ff75
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
feat: Add initial implementation of Vulnerability Resolver Jobs
- Created project for StellaOps.Scanner.Analyzers.Native.Tests with necessary dependencies.
- Documented roles and guidelines in AGENTS.md for Scheduler module.
- Implemented IResolverJobService interface and InMemoryResolverJobService for handling resolver jobs.
- Added ResolverBacklogNotifier and ResolverBacklogService for monitoring job metrics.
- Developed API endpoints for managing resolver jobs and retrieving metrics.
- Defined models for resolver job requests and responses.
- Integrated dependency injection for resolver job services.
- Implemented ImpactIndexSnapshot for persisting impact index data.
- Introduced SignalsScoringOptions for configurable scoring weights in reachability scoring.
- Added unit tests for ReachabilityScoringService and RuntimeFactsIngestionService.
- Created dotnet-filter.sh script to handle command-line arguments for dotnet.
- Established nuget-prime project for managing package downloads.
2025-11-18 07:52:15 +02:00

102 lines
4.1 KiB
C#

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using StellaOps.Auth.Abstractions;
using StellaOps.Scheduler.WebService.Auth;
namespace StellaOps.Scheduler.WebService.VulnerabilityResolverJobs;
public static class ResolverJobEndpointExtensions
{
private const string ScopeWrite = StellaOpsScopes.EffectiveWrite;
private const string ScopeRead = StellaOpsScopes.FindingsRead;
public static void MapResolverJobEndpoints(this IEndpointRouteBuilder builder)
{
var group = builder.MapGroup("/api/v1/scheduler/vuln/resolver");
group.MapPost("/jobs", CreateJobAsync);
group.MapGet("/jobs/{jobId}", GetJobAsync);
group.MapGet("/metrics", GetLagMetricsAsync);
}
internal static async Task<IResult> CreateJobAsync(
[FromBody] ResolverJobRequest request,
HttpContext httpContext,
[FromServices] ITenantContextAccessor tenantAccessor,
[FromServices] IScopeAuthorizer authorizer,
[FromServices] IResolverJobService jobService,
CancellationToken cancellationToken)
{
try
{
authorizer.EnsureScope(httpContext, ScopeWrite);
var tenant = tenantAccessor.GetTenant(httpContext);
var job = await jobService.CreateAsync(tenant.TenantId, request, cancellationToken).ConfigureAwait(false);
return Results.Created($"/api/v1/scheduler/vuln/resolver/jobs/{job.Id}", job);
}
catch (UnauthorizedAccessException ex)
{
return Results.Json(new { error = ex.Message }, statusCode: StatusCodes.Status401Unauthorized);
}
catch (InvalidOperationException ex)
{
return Results.Json(new { error = ex.Message }, statusCode: StatusCodes.Status403Forbidden);
}
catch (ValidationException ex)
{
return Results.Json(new { error = ex.Message }, statusCode: StatusCodes.Status400BadRequest);
}
}
internal static async Task<IResult> GetJobAsync(
string jobId,
HttpContext httpContext,
[FromServices] ITenantContextAccessor tenantAccessor,
[FromServices] IScopeAuthorizer authorizer,
[FromServices] IResolverJobService jobService,
CancellationToken cancellationToken)
{
try
{
authorizer.EnsureScope(httpContext, ScopeRead);
var tenant = tenantAccessor.GetTenant(httpContext);
var job = await jobService.GetAsync(tenant.TenantId, jobId, cancellationToken).ConfigureAwait(false);
return job is null ? Results.NotFound() : Results.Ok(job);
}
catch (UnauthorizedAccessException ex)
{
return Results.Json(new { error = ex.Message }, statusCode: StatusCodes.Status401Unauthorized);
}
catch (InvalidOperationException ex)
{
return Results.Json(new { error = ex.Message }, statusCode: StatusCodes.Status403Forbidden);
}
}
internal static IResult GetLagMetricsAsync(
HttpContext httpContext,
[FromServices] ITenantContextAccessor tenantAccessor,
[FromServices] IScopeAuthorizer authorizer,
[FromServices] IResolverJobService jobService,
[FromServices] IResolverBacklogService backlogService,
[FromServices] IResolverBacklogNotifier backlogNotifier)
{
try
{
authorizer.EnsureScope(httpContext, ScopeRead);
var tenant = tenantAccessor.GetTenant(httpContext);
var metrics = jobService.ComputeMetrics(tenant.TenantId);
var backlog = backlogService.GetSummary();
backlogNotifier.NotifyIfBreached(metrics with { Pending = (int)backlog.TotalDepth });
return Results.Ok(new { jobs = metrics, backlog });
}
catch (UnauthorizedAccessException ex)
{
return Results.Json(new { error = ex.Message }, statusCode: StatusCodes.Status401Unauthorized);
}
catch (InvalidOperationException ex)
{
return Results.Json(new { error = ex.Message }, statusCode: StatusCodes.Status403Forbidden);
}
}
}