Gaps fill up, fixes, ui restructuring
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using StellaOps.Scanner.WebService.Security;
|
||||
|
||||
namespace StellaOps.Scanner.WebService.Endpoints;
|
||||
|
||||
internal static class SecurityAdapterEndpoints
|
||||
{
|
||||
private static readonly DateTimeOffset SnapshotAt = DateTimeOffset.Parse("2026-02-19T03:15:00Z");
|
||||
|
||||
public static void MapSecurityAdapterEndpoints(this RouteGroupBuilder apiGroup)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(apiGroup);
|
||||
|
||||
var security = apiGroup.MapGroup("/security")
|
||||
.WithTags("Security");
|
||||
|
||||
security.MapGet("/findings", (
|
||||
[FromQuery] string? severity,
|
||||
[FromQuery] string? reachability,
|
||||
[FromQuery] string? environment) =>
|
||||
{
|
||||
var items = BuildFindings()
|
||||
.Where(item => string.IsNullOrWhiteSpace(severity) || string.Equals(item.Severity, severity, StringComparison.OrdinalIgnoreCase))
|
||||
.Where(item => string.IsNullOrWhiteSpace(reachability) || string.Equals(item.Reachability, reachability, StringComparison.OrdinalIgnoreCase))
|
||||
.Where(item => string.IsNullOrWhiteSpace(environment) || string.Equals(item.Environment, environment, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(item => item.FindingId, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
return Results.Ok(new SecurityFindingsResponseDto(
|
||||
SnapshotAt,
|
||||
BuildConfidence(),
|
||||
items,
|
||||
items.Count));
|
||||
})
|
||||
.WithName("SecurityFindingsAdapter")
|
||||
.WithSummary("Decision-first findings view with reachability context.")
|
||||
.RequireAuthorization(ScannerPolicies.ScansRead);
|
||||
|
||||
security.MapGet("/vulnerabilities", (
|
||||
[FromQuery] string? cve) =>
|
||||
{
|
||||
var items = BuildVulnerabilities()
|
||||
.Where(item => string.IsNullOrWhiteSpace(cve) || item.Cve.Contains(cve, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(item => item.Cve, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
return Results.Ok(new SecurityVulnerabilitiesResponseDto(
|
||||
SnapshotAt,
|
||||
items,
|
||||
items.Count));
|
||||
})
|
||||
.WithName("SecurityVulnerabilitiesAdapter")
|
||||
.WithSummary("Vulnerability catalog projection with environment impact counts.")
|
||||
.RequireAuthorization(ScannerPolicies.ScansRead);
|
||||
|
||||
security.MapGet("/vex", (
|
||||
[FromQuery] string? status) =>
|
||||
{
|
||||
var items = BuildVexStatements()
|
||||
.Where(item => string.IsNullOrWhiteSpace(status) || string.Equals(item.Status, status, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(item => item.StatementId, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
return Results.Ok(new SecurityVexResponseDto(
|
||||
SnapshotAt,
|
||||
items,
|
||||
items.Count));
|
||||
})
|
||||
.WithName("SecurityVexAdapter")
|
||||
.WithSummary("VEX statement projection linked to findings and trust state.")
|
||||
.RequireAuthorization(ScannerPolicies.ScansRead);
|
||||
|
||||
security.MapGet("/reachability", () =>
|
||||
{
|
||||
var items = BuildReachability()
|
||||
.OrderBy(item => item.Environment, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
return Results.Ok(new SecurityReachabilityResponseDto(
|
||||
SnapshotAt,
|
||||
BuildConfidence(),
|
||||
items));
|
||||
})
|
||||
.WithName("SecurityReachabilityAdapter")
|
||||
.WithSummary("Reachability summary projection by environment.")
|
||||
.RequireAuthorization(ScannerPolicies.ScansRead);
|
||||
}
|
||||
|
||||
private static SecurityDataConfidenceDto BuildConfidence()
|
||||
{
|
||||
return new SecurityDataConfidenceDto(
|
||||
Status: "warning",
|
||||
Summary: "NVD freshness lag and runtime ingest delay reduce confidence.",
|
||||
NvdStalenessHours: 3,
|
||||
PendingRescans: 12,
|
||||
RuntimeDlqDepth: 1230);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<SecurityFindingRowDto> BuildFindings()
|
||||
{
|
||||
return
|
||||
[
|
||||
new SecurityFindingRowDto("finding-0001", "CVE-2026-1234", "us-prod", "user-service", "critical", "reachable", "0/1/0", "stale"),
|
||||
new SecurityFindingRowDto("finding-0002", "CVE-2026-2222", "us-uat", "billing-worker", "critical", "reachable", "0/1/0", "stale"),
|
||||
new SecurityFindingRowDto("finding-0003", "CVE-2026-9001", "us-prod", "api-gateway", "high", "not_reachable", "1/1/1", "fresh"),
|
||||
];
|
||||
}
|
||||
|
||||
private static IReadOnlyList<SecurityVulnerabilityRowDto> BuildVulnerabilities()
|
||||
{
|
||||
return
|
||||
[
|
||||
new SecurityVulnerabilityRowDto("CVE-2026-1234", "critical", AffectedEnvironments: 1, ReachableEnvironments: 1, VexStatus: "under_investigation"),
|
||||
new SecurityVulnerabilityRowDto("CVE-2026-2222", "critical", AffectedEnvironments: 1, ReachableEnvironments: 1, VexStatus: "none"),
|
||||
new SecurityVulnerabilityRowDto("CVE-2026-9001", "high", AffectedEnvironments: 2, ReachableEnvironments: 0, VexStatus: "not_affected"),
|
||||
];
|
||||
}
|
||||
|
||||
private static IReadOnlyList<SecurityVexStatementRowDto> BuildVexStatements()
|
||||
{
|
||||
return
|
||||
[
|
||||
new SecurityVexStatementRowDto("vex-0001", "CVE-2026-9001", "not_affected", "vendor-a", "trusted", "2026-02-19T01:10:00Z"),
|
||||
new SecurityVexStatementRowDto("vex-0002", "CVE-2026-1234", "under_investigation", "internal-sec", "trusted", "2026-02-19T00:22:00Z"),
|
||||
new SecurityVexStatementRowDto("vex-0003", "CVE-2026-2222", "affected", "vendor-b", "unverified", "2026-02-18T19:02:00Z"),
|
||||
];
|
||||
}
|
||||
|
||||
private static IReadOnlyList<SecurityReachabilityRowDto> BuildReachability()
|
||||
{
|
||||
return
|
||||
[
|
||||
new SecurityReachabilityRowDto("apac-prod", CriticalReachable: 0, HighReachable: 0, RuntimeCoveragePercent: 86),
|
||||
new SecurityReachabilityRowDto("eu-prod", CriticalReachable: 0, HighReachable: 1, RuntimeCoveragePercent: 89),
|
||||
new SecurityReachabilityRowDto("us-prod", CriticalReachable: 2, HighReachable: 1, RuntimeCoveragePercent: 41),
|
||||
new SecurityReachabilityRowDto("us-uat", CriticalReachable: 1, HighReachable: 2, RuntimeCoveragePercent: 62),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record SecurityFindingsResponseDto(
|
||||
DateTimeOffset GeneratedAt,
|
||||
SecurityDataConfidenceDto DataConfidence,
|
||||
IReadOnlyList<SecurityFindingRowDto> Items,
|
||||
int Total);
|
||||
|
||||
public sealed record SecurityFindingRowDto(
|
||||
string FindingId,
|
||||
string Cve,
|
||||
string Environment,
|
||||
string Component,
|
||||
string Severity,
|
||||
string Reachability,
|
||||
string HybridEvidence,
|
||||
string SbomFreshness);
|
||||
|
||||
public sealed record SecurityVulnerabilitiesResponseDto(
|
||||
DateTimeOffset GeneratedAt,
|
||||
IReadOnlyList<SecurityVulnerabilityRowDto> Items,
|
||||
int Total);
|
||||
|
||||
public sealed record SecurityVulnerabilityRowDto(
|
||||
string Cve,
|
||||
string Severity,
|
||||
int AffectedEnvironments,
|
||||
int ReachableEnvironments,
|
||||
string VexStatus);
|
||||
|
||||
public sealed record SecurityVexResponseDto(
|
||||
DateTimeOffset GeneratedAt,
|
||||
IReadOnlyList<SecurityVexStatementRowDto> Items,
|
||||
int Total);
|
||||
|
||||
public sealed record SecurityVexStatementRowDto(
|
||||
string StatementId,
|
||||
string Cve,
|
||||
string Status,
|
||||
string Issuer,
|
||||
string TrustStatus,
|
||||
string SignedAt);
|
||||
|
||||
public sealed record SecurityReachabilityResponseDto(
|
||||
DateTimeOffset GeneratedAt,
|
||||
SecurityDataConfidenceDto DataConfidence,
|
||||
IReadOnlyList<SecurityReachabilityRowDto> Items);
|
||||
|
||||
public sealed record SecurityReachabilityRowDto(
|
||||
string Environment,
|
||||
int CriticalReachable,
|
||||
int HighReachable,
|
||||
int RuntimeCoveragePercent);
|
||||
|
||||
public sealed record SecurityDataConfidenceDto(
|
||||
string Status,
|
||||
string Summary,
|
||||
int NvdStalenessHours,
|
||||
int PendingRescans,
|
||||
int RuntimeDlqDepth);
|
||||
@@ -636,6 +636,7 @@ apiGroup.MapTriageInboxEndpoints();
|
||||
apiGroup.MapBatchTriageEndpoints();
|
||||
apiGroup.MapProofBundleEndpoints();
|
||||
apiGroup.MapSecretDetectionSettingsEndpoints(); // Sprint: SPRINT_20260104_006_BE
|
||||
apiGroup.MapSecurityAdapterEndpoints(); // Pack v2 security adapter routes
|
||||
|
||||
if (resolvedOptions.Features.EnablePolicyPreview)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user