save dev progress

This commit is contained in:
StellaOps Bot
2025-12-26 00:32:35 +02:00
parent aa70af062e
commit ed3079543c
142 changed files with 23771 additions and 232 deletions

View File

@@ -411,6 +411,40 @@ public sealed record BucketThresholdsDto
public required int InvestigateMin { get; init; }
}
/// <summary>
/// Response for listing policy versions.
/// Sprint: SPRINT_8200_0012_0004 - Task API-8200-029
/// </summary>
public sealed record PolicyVersionListResponse
{
/// <summary>List of available policy versions.</summary>
public required IReadOnlyList<PolicyVersionSummary> Versions { get; init; }
/// <summary>Currently active version.</summary>
public required string ActiveVersion { get; init; }
}
/// <summary>
/// Summary of a policy version.
/// </summary>
public sealed record PolicyVersionSummary
{
/// <summary>Version identifier.</summary>
public required string Version { get; init; }
/// <summary>Content digest.</summary>
public required string Digest { get; init; }
/// <summary>Environment/profile (production, staging, etc.).</summary>
public required string Environment { get; init; }
/// <summary>When this version was created.</summary>
public required DateTimeOffset CreatedAt { get; init; }
/// <summary>Whether this is the currently active version.</summary>
public required bool IsActive { get; init; }
}
/// <summary>
/// Webhook registration response.
/// </summary>

View File

@@ -85,6 +85,15 @@ public static class ScoringEndpoints
.RequireAuthorization(ScoringReadPolicy)
.Produces<ScoringPolicyResponse>(200)
.Produces(404);
// GET /api/v1/scoring/policy/versions - List all policy versions
// Rate limit: 100/min (via API Gateway)
// Task: API-8200-029
scoringGroup.MapGet("/policy/versions", ListPolicyVersions)
.WithName("ListScoringPolicyVersions")
.WithDescription("List all available scoring policy versions")
.RequireAuthorization(ScoringReadPolicy)
.Produces<PolicyVersionListResponse>(200);
}
private static async Task<Results<Ok<EvidenceWeightedScoreResponse>, NotFound<ScoringErrorResponse>, BadRequest<ScoringErrorResponse>>> CalculateScore(
@@ -218,4 +227,12 @@ public static class ScoringEndpoints
return TypedResults.Ok(policy);
}
private static async Task<Ok<PolicyVersionListResponse>> ListPolicyVersions(
IFindingScoringService service,
CancellationToken ct)
{
var versions = await service.ListPolicyVersionsAsync(ct);
return TypedResults.Ok(versions);
}
}

View File

@@ -2004,3 +2004,11 @@ static Guid? ParseGuid(string value)
{
return Guid.TryParse(value, out var result) ? result : null;
}
namespace StellaOps.Findings.Ledger.WebService
{
/// <summary>
/// Marker class for WebApplicationFactory integration tests.
/// </summary>
public partial class Program { }
}

View File

@@ -59,6 +59,12 @@ public interface IFindingScoringService
/// Get specific policy version.
/// </summary>
Task<ScoringPolicyResponse?> GetPolicyVersionAsync(string version, CancellationToken ct);
/// <summary>
/// List all available policy versions.
/// Task: API-8200-029
/// </summary>
Task<PolicyVersionListResponse> ListPolicyVersionsAsync(CancellationToken ct);
}
/// <summary>
@@ -326,6 +332,32 @@ public sealed class FindingScoringService : IFindingScoringService
return MapPolicyToResponse(policy);
}
public async Task<PolicyVersionListResponse> ListPolicyVersionsAsync(CancellationToken ct)
{
// Get known policy versions/environments
var environments = new[] { "production", "staging", "development" };
var versions = new List<PolicyVersionSummary>();
foreach (var env in environments)
{
var policy = await _policyProvider.GetDefaultPolicyAsync(env, ct);
versions.Add(new PolicyVersionSummary
{
Version = policy.Version,
Digest = policy.ComputeDigest(),
Environment = env,
CreatedAt = policy.CreatedAt,
IsActive = env == _environment
});
}
return new PolicyVersionListResponse
{
Versions = versions,
ActiveVersion = versions.FirstOrDefault(v => v.IsActive)?.Version ?? versions[0].Version
};
}
private static string GetCacheKey(string findingId) => $"ews:score:{findingId}";
private static EvidenceWeightedScoreResponse MapToResponse(