feat(rate-limiting): Implement core rate limiting functionality with configuration, decision-making, metrics, middleware, and service registration
- Add RateLimitConfig for configuration management with YAML binding support. - Introduce RateLimitDecision to encapsulate the result of rate limit checks. - Implement RateLimitMetrics for OpenTelemetry metrics tracking. - Create RateLimitMiddleware for enforcing rate limits on incoming requests. - Develop RateLimitService to orchestrate instance and environment rate limit checks. - Add RateLimitServiceCollectionExtensions for dependency injection registration.
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using StellaOps.Scanner.SmartDiff.Detection;
|
||||
using StellaOps.Scanner.SmartDiff.Output;
|
||||
using StellaOps.Scanner.Storage.Postgres;
|
||||
using StellaOps.Scanner.WebService.Security;
|
||||
|
||||
@@ -10,6 +12,7 @@ namespace StellaOps.Scanner.WebService.Endpoints;
|
||||
/// <summary>
|
||||
/// Smart-Diff API endpoints for material risk changes and VEX candidates.
|
||||
/// Per Sprint 3500.3 - Smart-Diff Detection Rules.
|
||||
/// Task SDIFF-BIN-029 - API endpoint `GET /scans/{id}/sarif`
|
||||
/// </summary>
|
||||
internal static class SmartDiffEndpoints
|
||||
{
|
||||
@@ -27,6 +30,14 @@ internal static class SmartDiffEndpoints
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.RequireAuthorization(ScannerPolicies.ScansRead);
|
||||
|
||||
// SARIF output endpoint (Task SDIFF-BIN-029)
|
||||
group.MapGet("/scans/{scanId}/sarif", HandleGetScanSarifAsync)
|
||||
.WithName("scanner.smartdiff.sarif")
|
||||
.WithTags("SmartDiff", "SARIF")
|
||||
.Produces(StatusCodes.Status200OK, contentType: "application/sarif+json")
|
||||
.Produces(StatusCodes.Status404NotFound)
|
||||
.RequireAuthorization(ScannerPolicies.ScansRead);
|
||||
|
||||
// VEX candidate endpoints
|
||||
group.MapGet("/images/{digest}/candidates", HandleGetCandidatesAsync)
|
||||
.WithName("scanner.smartdiff.candidates")
|
||||
@@ -51,6 +62,81 @@ internal static class SmartDiffEndpoints
|
||||
.RequireAuthorization(ScannerPolicies.ScansWrite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GET /smart-diff/scans/{scanId}/sarif - Get Smart-Diff results as SARIF 2.1.0.
|
||||
/// Task: SDIFF-BIN-029
|
||||
/// </summary>
|
||||
private static async Task<IResult> HandleGetScanSarifAsync(
|
||||
string scanId,
|
||||
IMaterialRiskChangeRepository changeRepo,
|
||||
IVexCandidateStore candidateStore,
|
||||
IScanMetadataRepository? metadataRepo = null,
|
||||
bool? pretty = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
// Gather all data for the scan
|
||||
var changes = await changeRepo.GetChangesForScanAsync(scanId, ct);
|
||||
|
||||
// Get scan metadata if available
|
||||
string? baseDigest = null;
|
||||
string? targetDigest = null;
|
||||
DateTimeOffset scanTime = DateTimeOffset.UtcNow;
|
||||
|
||||
if (metadataRepo is not null)
|
||||
{
|
||||
var metadata = await metadataRepo.GetScanMetadataAsync(scanId, ct);
|
||||
if (metadata is not null)
|
||||
{
|
||||
baseDigest = metadata.BaseDigest;
|
||||
targetDigest = metadata.TargetDigest;
|
||||
scanTime = metadata.ScanTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to SARIF input format
|
||||
var sarifInput = new SmartDiffSarifInput(
|
||||
ScannerVersion: GetScannerVersion(),
|
||||
ScanTime: scanTime,
|
||||
BaseDigest: baseDigest,
|
||||
TargetDigest: targetDigest,
|
||||
MaterialChanges: changes.Select(c => new MaterialRiskChange(
|
||||
VulnId: c.VulnId,
|
||||
ComponentPurl: c.ComponentPurl,
|
||||
Direction: c.IsRiskIncrease ? RiskDirection.Increased : RiskDirection.Decreased,
|
||||
Reason: c.ChangeReason,
|
||||
FilePath: c.FilePath
|
||||
)).ToList(),
|
||||
HardeningRegressions: [],
|
||||
VexCandidates: [],
|
||||
ReachabilityChanges: []);
|
||||
|
||||
// Generate SARIF
|
||||
var options = new SarifOutputOptions
|
||||
{
|
||||
IndentedJson = pretty == true,
|
||||
IncludeVexCandidates = true,
|
||||
IncludeHardeningRegressions = true,
|
||||
IncludeReachabilityChanges = true
|
||||
};
|
||||
|
||||
var generator = new SarifOutputGenerator();
|
||||
var sarifJson = generator.Generate(sarifInput, options);
|
||||
|
||||
// Return as SARIF content type with proper filename
|
||||
var fileName = $"smartdiff-{scanId}.sarif";
|
||||
return Results.Text(
|
||||
sarifJson,
|
||||
contentType: "application/sarif+json",
|
||||
statusCode: StatusCodes.Status200OK);
|
||||
}
|
||||
|
||||
private static string GetScannerVersion()
|
||||
{
|
||||
var assembly = typeof(SmartDiffEndpoints).Assembly;
|
||||
var version = assembly.GetName().Version;
|
||||
return version?.ToString() ?? "1.0.0";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GET /smart-diff/scans/{scanId}/changes - Get material risk changes for a scan.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user