more audit work

This commit is contained in:
master
2026-01-08 10:21:51 +02:00
parent 43c02081ef
commit 51cf4bc16c
546 changed files with 36721 additions and 4003 deletions

View File

@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Auth.Abstractions;
using StellaOps.Auth.ServerIntegration;
using LedgerProgram = StellaOps.Findings.Ledger.WebService.Program;
namespace StellaOps.Findings.Ledger.Tests;
internal sealed class FindingsLedgerWebApplicationFactory : WebApplicationFactory<LedgerProgram>
{
private static readonly IReadOnlyDictionary<string, string?> DefaultEnvironment =
new Dictionary<string, string?>(StringComparer.Ordinal)
{
["FINDINGS_LEDGER_FINDINGS__LEDGER__DATABASE__CONNECTIONSTRING"] = "Host=localhost;Database=stellaops_test;Username=stella;Password=stella",
["FINDINGS_LEDGER_FINDINGS__LEDGER__ATTACHMENTS__ENCRYPTIONKEY"] = "test-encryption-key",
["FINDINGS_LEDGER_FINDINGS__LEDGER__ATTACHMENTS__SIGNEDURLSECRET"] = "test-signed-url-secret",
["FINDINGS_LEDGER_FINDINGS__LEDGER__ATTACHMENTS__CSRFSHAREDSECRET"] = "test-csrf-secret",
["FINDINGS_LEDGER_FINDINGS__LEDGER__AUTHORITY__ISSUER"] = "https://authority.local",
["FINDINGS_LEDGER_FINDINGS__LEDGER__AUTHORITY__REQUIREHTTPSMETADATA"] = "false",
["FINDINGS_LEDGER_FINDINGS__LEDGER__AUTHORITY__REQUIREDSCOPES__0"] = StellaOpsScopes.FindingsRead,
["FINDINGS_LEDGER_FINDINGS__LEDGER__AUTHORITY__REQUIREDSCOPES__1"] = "findings:write"
};
private readonly Dictionary<string, string?> originalEnvironment = new(StringComparer.Ordinal);
public FindingsLedgerWebApplicationFactory()
{
foreach (var pair in DefaultEnvironment)
{
originalEnvironment[pair.Key] = Environment.GetEnvironmentVariable(pair.Key);
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
}
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Production");
builder.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = false;
options.ValidateOnBuild = false;
});
builder.ConfigureAppConfiguration((context, configBuilder) =>
{
configBuilder.AddInMemoryCollection(new Dictionary<string, string?>
{
["findings:ledger:database:connectionString"] = "Host=localhost;Database=stellaops_test;Username=stella;Password=stella",
["findings:ledger:attachments:encryptionKey"] = "test-encryption-key",
["findings:ledger:attachments:signedUrlSecret"] = "test-signed-url-secret",
["findings:ledger:attachments:csrfSharedSecret"] = "test-csrf-secret",
["findings:ledger:authority:issuer"] = "https://authority.local",
["findings:ledger:authority:requireHttpsMetadata"] = "false",
["findings:ledger:authority:requiredScopes:0"] = StellaOpsScopes.FindingsRead,
["findings:ledger:authority:requiredScopes:1"] = "findings:write"
});
});
builder.ConfigureTestServices(services =>
{
services.RemoveAll<IHostedService>();
services.RemoveAll<IConfigureOptions<AuthenticationOptions>>();
services.RemoveAll<IPostConfigureOptions<AuthenticationOptions>>();
services.RemoveAll<IConfigureOptions<JwtBearerOptions>>();
services.RemoveAll<IPostConfigureOptions<JwtBearerOptions>>();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = FindingsLedgerTestAuthHandler.SchemeName;
options.DefaultChallengeScheme = FindingsLedgerTestAuthHandler.SchemeName;
})
.AddScheme<AuthenticationSchemeOptions, FindingsLedgerTestAuthHandler>(
FindingsLedgerTestAuthHandler.SchemeName,
_ => { })
.AddScheme<AuthenticationSchemeOptions, FindingsLedgerTestAuthHandler>(
StellaOpsAuthenticationDefaults.AuthenticationScheme,
_ => { });
});
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
{
return;
}
foreach (var pair in originalEnvironment)
{
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
}
}
}
internal sealed class FindingsLedgerTestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
internal const string SchemeName = "FindingsLedgerTest";
public FindingsLedgerTestAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder)
: base(options, logger, encoder)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.TryGetValue("Authorization", out var rawHeader) ||
!AuthenticationHeaderValue.TryParse(rawHeader, out var header))
{
return Task.FromResult(AuthenticateResult.NoResult());
}
if (!string.Equals(header.Scheme, "Bearer", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(header.Scheme, SchemeName, StringComparison.OrdinalIgnoreCase))
{
return Task.FromResult(AuthenticateResult.NoResult());
}
if (!string.Equals(header.Parameter, "test-token", StringComparison.Ordinal))
{
return Task.FromResult(AuthenticateResult.Fail("Invalid test token."));
}
var claims = new List<Claim>
{
new(StellaOpsClaimTypes.Subject, "test-user")
};
if (Request.Headers.TryGetValue("X-Tenant-Id", out var tenantValue) &&
Guid.TryParse(tenantValue.ToString(), out var tenantId))
{
claims.Add(new Claim(StellaOpsClaimTypes.Tenant, tenantId.ToString("D")));
}
if (Request.Headers.TryGetValue("X-Scopes", out var scopesValue))
{
var scopes = scopesValue
.ToString()
.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (scopes.Length > 0)
{
claims.Add(new Claim(StellaOpsClaimTypes.Scope, string.Join(' ', scopes)));
}
}
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return Task.FromResult(AuthenticateResult.Success(ticket));
}
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.Headers["WWW-Authenticate"] = "Bearer";
return base.HandleChallengeAsync(properties);
}
}

View File

@@ -10,8 +10,6 @@ using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.TestKit;
@@ -23,20 +21,13 @@ namespace StellaOps.Findings.Ledger.Tests;
/// </summary>
public sealed class FindingsLedgerWebServiceContractTests : IDisposable
{
private readonly WebApplicationFactory<Program> _factory;
private readonly FindingsLedgerWebApplicationFactory _factory;
private readonly HttpClient _client;
private bool _disposed;
public FindingsLedgerWebServiceContractTests()
{
_factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
// Configure test services as needed
});
});
_factory = new FindingsLedgerWebApplicationFactory();
_client = _factory.CreateClient();
}

View File

@@ -17,6 +17,8 @@
<None Include="**/tools/**/*" Pack="false" CopyToOutputDirectory="Never" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../Authority/StellaOps.Authority/StellaOps.Auth.Abstractions/StellaOps.Auth.Abstractions.csproj" />
<ProjectReference Include="../../Authority/StellaOps.Authority/StellaOps.Auth.ServerIntegration/StellaOps.Auth.ServerIntegration.csproj" />
<ProjectReference Include="../StellaOps.Findings.Ledger/StellaOps.Findings.Ledger.csproj" />
<ProjectReference Include="../StellaOps.Findings.Ledger.WebService/StellaOps.Findings.Ledger.WebService.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
@@ -26,4 +28,4 @@
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Moq" />
</ItemGroup>
</Project>
</Project>

View File

@@ -8,3 +8,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
| AUDIT-0344-M | DONE | Revalidated 2026-01-07; maintainability audit for Findings.Ledger.Tests. |
| AUDIT-0344-T | DONE | Revalidated 2026-01-07; test coverage audit for Findings.Ledger.Tests. |
| AUDIT-0344-A | DONE | Waived (test project; revalidated 2026-01-07). |
| LEDGER-TESTS-0001 | DOING | Stabilize Findings Ledger WebService test harness (config/auth + stubs). |

View File

@@ -1,3 +1,4 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using StellaOps.Findings.Ledger.WebService.Contracts;
@@ -14,12 +15,20 @@ public static class FindingSummaryEndpoints
.RequireAuthorization();
// GET /api/v1/findings/{findingId}/summary
group.MapGet("/{findingId:guid}/summary", async Task<Results<Ok<FindingSummary>, NotFound>> (
Guid findingId,
group.MapGet("/{findingId}/summary", async Task<Results<Ok<FindingSummary>, NotFound, ProblemHttpResult>> (
string findingId,
IFindingSummaryService service,
CancellationToken ct) =>
{
var summary = await service.GetSummaryAsync(findingId, ct);
if (!Guid.TryParse(findingId, out var parsedId))
{
return TypedResults.Problem(
statusCode: StatusCodes.Status400BadRequest,
title: "invalid_finding_id",
detail: "findingId must be a valid GUID.");
}
var summary = await service.GetSummaryAsync(parsedId, ct);
return summary is not null
? TypedResults.Ok(summary)
: TypedResults.NotFound();
@@ -27,6 +36,7 @@ public static class FindingSummaryEndpoints
.WithName("GetFindingSummary")
.WithDescription("Get condensed finding summary for vulnerability-first UX")
.Produces<FindingSummary>(200)
.ProducesProblem(StatusCodes.Status400BadRequest)
.Produces(404);
// GET /api/v1/findings/summaries

View File

@@ -213,6 +213,17 @@ builder.Services.AddSingleton<StellaOps.Findings.Ledger.Infrastructure.Snapshot.
builder.Services.AddSingleton<SnapshotService>();
builder.Services.AddSingleton<VexConsensusService>();
// Finding summary, evidence graph, reachability, and runtime timeline endpoints
builder.Services.AddSingleton<IFindingSummaryBuilder, FindingSummaryBuilder>();
builder.Services.AddSingleton<IFindingRepository, InMemoryFindingRepository>();
builder.Services.AddSingleton<IFindingSummaryService, FindingSummaryService>();
builder.Services.AddSingleton<IEvidenceRepository, NullEvidenceRepository>();
builder.Services.AddSingleton<IAttestationVerifier, NullAttestationVerifier>();
builder.Services.AddSingleton<IEvidenceGraphBuilder, EvidenceGraphBuilder>();
builder.Services.AddSingleton<IEvidenceContentService, NullEvidenceContentService>();
builder.Services.AddSingleton<IReachabilityMapService, NullReachabilityMapService>();
builder.Services.AddSingleton<IRuntimeTimelineService, NullRuntimeTimelineService>();
// Alert and Decision services (SPRINT_3602)
builder.Services.AddSingleton<IAlertService, AlertService>();
builder.Services.AddSingleton<IDecisionService, DecisionService>();
@@ -1909,6 +1920,12 @@ app.MapPatch("/api/v1/findings/{findingId}/state", async Task<Results<Ok<StateTr
// Refresh Router endpoint cache
app.TryRefreshStellaRouterEndpoints(routerOptions);
// Findings summary, evidence graph, reachability, and runtime timeline endpoints
app.MapFindingSummaryEndpoints();
app.MapEvidenceGraphEndpoints();
app.MapReachabilityMapEndpoints();
app.MapRuntimeTimelineEndpoints();
// Map EWS scoring and webhook endpoints (SPRINT_8200.0012.0004)
app.MapScoringEndpoints();
app.MapWebhookEndpoints();

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using StellaOps.Findings.Ledger.WebService.Endpoints;
using StellaOps.Scanner.Analyzers.Native.RuntimeCapture.Timeline;
using StellaOps.Scanner.Reachability.MiniMap;
namespace StellaOps.Findings.Ledger.WebService.Services;
internal sealed class InMemoryFindingRepository : IFindingRepository
{
public Task<FindingData?> GetByIdAsync(Guid id, CancellationToken ct)
=> Task.FromResult<FindingData?>(null);
public Task<(IReadOnlyList<FindingData> findings, int totalCount)> GetPagedAsync(
int page,
int pageSize,
string? status,
string? severity,
decimal? minConfidence,
CancellationToken ct)
{
IReadOnlyList<FindingData> findings = Array.Empty<FindingData>();
return Task.FromResult((findings, 0));
}
}
internal sealed class NullEvidenceRepository : IEvidenceRepository
{
public Task<FullEvidence?> GetFullEvidenceAsync(Guid findingId, CancellationToken ct)
=> Task.FromResult<FullEvidence?>(null);
}
internal sealed class NullAttestationVerifier : IAttestationVerifier
{
private static readonly AttestationVerificationResult DefaultResult = new()
{
IsValid = false,
SignerIdentity = null,
SignedAt = null,
KeyId = null,
RekorLogIndex = null
};
public Task<AttestationVerificationResult> VerifyAsync(string digest, CancellationToken ct)
=> Task.FromResult(DefaultResult);
}
internal sealed class NullEvidenceContentService : IEvidenceContentService
{
public Task<object?> GetContentAsync(Guid findingId, string nodeId, CancellationToken ct)
=> Task.FromResult<object?>(null);
}
internal sealed class NullReachabilityMapService : IReachabilityMapService
{
public Task<ReachabilityMiniMap?> GetMiniMapAsync(Guid findingId, int maxPaths, CancellationToken ct)
=> Task.FromResult<ReachabilityMiniMap?>(null);
}
internal sealed class NullRuntimeTimelineService : IRuntimeTimelineService
{
public Task<RuntimeTimeline?> GetTimelineAsync(Guid findingId, TimelineOptions options, CancellationToken ct)
=> Task.FromResult<RuntimeTimeline?>(null);
}

View File

@@ -8,3 +8,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
| AUDIT-0345-M | DONE | Revalidated 2026-01-07; maintainability audit for Findings.Ledger.WebService. |
| AUDIT-0345-T | DONE | Revalidated 2026-01-07; test coverage audit for Findings.Ledger.WebService. |
| AUDIT-0345-A | TODO | Pending approval (non-test project; revalidated 2026-01-07). |
| LEDGER-TESTS-0001 | DOING | Stabilize Findings Ledger WebService test harness (config/auth + stubs). |

View File

@@ -10,8 +10,6 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using LedgerProgram = StellaOps.Findings.Ledger.WebService.Program;
namespace StellaOps.Findings.Ledger.Tests.Integration;
/// <summary>
@@ -19,11 +17,11 @@ namespace StellaOps.Findings.Ledger.Tests.Integration;
/// </summary>
[Trait("Category", "Integration")]
[Trait("Sprint", "3602")]
public sealed class EvidenceDecisionApiIntegrationTests : IClassFixture<WebApplicationFactory<LedgerProgram>>
public sealed class EvidenceDecisionApiIntegrationTests : IClassFixture<FindingsLedgerWebApplicationFactory>
{
private readonly HttpClient _client;
public EvidenceDecisionApiIntegrationTests(WebApplicationFactory<LedgerProgram> factory)
public EvidenceDecisionApiIntegrationTests(FindingsLedgerWebApplicationFactory factory)
{
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{

View File

@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Auth.Abstractions;
using StellaOps.Auth.ServerIntegration;
using LedgerProgram = StellaOps.Findings.Ledger.WebService.Program;
namespace StellaOps.Findings.Ledger.Tests.Integration;
public sealed class FindingsLedgerWebApplicationFactory : WebApplicationFactory<LedgerProgram>
{
private static readonly IReadOnlyDictionary<string, string?> DefaultEnvironment =
new Dictionary<string, string?>(StringComparer.Ordinal)
{
["FINDINGS_LEDGER_FINDINGS__LEDGER__DATABASE__CONNECTIONSTRING"] = "Host=localhost;Database=stellaops_test;Username=stella;Password=stella",
["FINDINGS_LEDGER_FINDINGS__LEDGER__ATTACHMENTS__ENCRYPTIONKEY"] = "test-encryption-key",
["FINDINGS_LEDGER_FINDINGS__LEDGER__ATTACHMENTS__SIGNEDURLSECRET"] = "test-signed-url-secret",
["FINDINGS_LEDGER_FINDINGS__LEDGER__ATTACHMENTS__CSRFSHAREDSECRET"] = "test-csrf-secret",
["FINDINGS_LEDGER_FINDINGS__LEDGER__AUTHORITY__ISSUER"] = "https://authority.local",
["FINDINGS_LEDGER_FINDINGS__LEDGER__AUTHORITY__REQUIREHTTPSMETADATA"] = "false",
["FINDINGS_LEDGER_FINDINGS__LEDGER__AUTHORITY__REQUIREDSCOPES__0"] = StellaOpsScopes.FindingsRead,
["FINDINGS_LEDGER_FINDINGS__LEDGER__AUTHORITY__REQUIREDSCOPES__1"] = "findings:write"
};
private readonly Dictionary<string, string?> originalEnvironment = new(StringComparer.Ordinal);
public FindingsLedgerWebApplicationFactory()
{
foreach (var pair in DefaultEnvironment)
{
originalEnvironment[pair.Key] = Environment.GetEnvironmentVariable(pair.Key);
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
}
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Production");
builder.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = false;
options.ValidateOnBuild = false;
});
builder.ConfigureAppConfiguration((context, configBuilder) =>
{
configBuilder.AddInMemoryCollection(new Dictionary<string, string?>
{
["findings:ledger:database:connectionString"] = "Host=localhost;Database=stellaops_test;Username=stella;Password=stella",
["findings:ledger:attachments:encryptionKey"] = "test-encryption-key",
["findings:ledger:attachments:signedUrlSecret"] = "test-signed-url-secret",
["findings:ledger:attachments:csrfSharedSecret"] = "test-csrf-secret",
["findings:ledger:authority:issuer"] = "https://authority.local",
["findings:ledger:authority:requireHttpsMetadata"] = "false",
["findings:ledger:authority:requiredScopes:0"] = StellaOpsScopes.FindingsRead,
["findings:ledger:authority:requiredScopes:1"] = "findings:write"
});
});
builder.ConfigureTestServices(services =>
{
services.RemoveAll<IHostedService>();
services.RemoveAll<IConfigureOptions<AuthenticationOptions>>();
services.RemoveAll<IPostConfigureOptions<AuthenticationOptions>>();
services.RemoveAll<IConfigureOptions<JwtBearerOptions>>();
services.RemoveAll<IPostConfigureOptions<JwtBearerOptions>>();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = FindingsLedgerTestAuthHandler.SchemeName;
options.DefaultChallengeScheme = FindingsLedgerTestAuthHandler.SchemeName;
})
.AddScheme<AuthenticationSchemeOptions, FindingsLedgerTestAuthHandler>(
FindingsLedgerTestAuthHandler.SchemeName,
_ => { })
.AddScheme<AuthenticationSchemeOptions, FindingsLedgerTestAuthHandler>(
StellaOpsAuthenticationDefaults.AuthenticationScheme,
_ => { });
});
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
{
return;
}
foreach (var pair in originalEnvironment)
{
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
}
}
}
internal sealed class FindingsLedgerTestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
internal const string SchemeName = "FindingsLedgerTest";
public FindingsLedgerTestAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder)
: base(options, logger, encoder)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.TryGetValue("Authorization", out var rawHeader) ||
!AuthenticationHeaderValue.TryParse(rawHeader, out var header))
{
return Task.FromResult(AuthenticateResult.NoResult());
}
if (!string.Equals(header.Scheme, "Bearer", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(header.Scheme, SchemeName, StringComparison.OrdinalIgnoreCase))
{
return Task.FromResult(AuthenticateResult.NoResult());
}
if (!string.Equals(header.Parameter, "test-token", StringComparison.Ordinal))
{
return Task.FromResult(AuthenticateResult.Fail("Invalid test token."));
}
var claims = new List<Claim>
{
new(StellaOpsClaimTypes.Subject, "test-user")
};
if (Request.Headers.TryGetValue("X-Tenant-Id", out var tenantValue) &&
Guid.TryParse(tenantValue.ToString(), out var tenantId))
{
claims.Add(new Claim(StellaOpsClaimTypes.Tenant, tenantId.ToString("D")));
}
if (Request.Headers.TryGetValue("X-Scopes", out var scopesValue))
{
var scopes = scopesValue
.ToString()
.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (scopes.Length > 0)
{
claims.Add(new Claim(StellaOpsClaimTypes.Scope, string.Join(' ', scopes)));
}
}
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return Task.FromResult(AuthenticateResult.Success(ticket));
}
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.Headers["WWW-Authenticate"] = "Bearer";
return base.HandleChallengeAsync(properties);
}
}

View File

@@ -11,8 +11,6 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using LedgerProgram = StellaOps.Findings.Ledger.WebService.Program;
namespace StellaOps.Findings.Ledger.Tests.Integration;
/// <summary>
@@ -20,11 +18,11 @@ namespace StellaOps.Findings.Ledger.Tests.Integration;
/// </summary>
[Trait("Category", "Integration")]
[Trait("Sprint", "8200.0012.0004")]
public sealed class ScoringAuthorizationTests : IClassFixture<WebApplicationFactory<LedgerProgram>>
public sealed class ScoringAuthorizationTests : IClassFixture<FindingsLedgerWebApplicationFactory>
{
private readonly HttpClient _client;
public ScoringAuthorizationTests(WebApplicationFactory<LedgerProgram> factory)
public ScoringAuthorizationTests(FindingsLedgerWebApplicationFactory factory)
{
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{

View File

@@ -11,8 +11,6 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using LedgerProgram = StellaOps.Findings.Ledger.WebService.Program;
namespace StellaOps.Findings.Ledger.Tests.Integration;
/// <summary>
@@ -20,11 +18,11 @@ namespace StellaOps.Findings.Ledger.Tests.Integration;
/// </summary>
[Trait("Category", "Integration")]
[Trait("Sprint", "8200.0012.0004")]
public sealed class ScoringEndpointsIntegrationTests : IClassFixture<WebApplicationFactory<LedgerProgram>>
public sealed class ScoringEndpointsIntegrationTests : IClassFixture<FindingsLedgerWebApplicationFactory>
{
private readonly HttpClient _client;
public ScoringEndpointsIntegrationTests(WebApplicationFactory<LedgerProgram> factory)
public ScoringEndpointsIntegrationTests(FindingsLedgerWebApplicationFactory factory)
{
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{

View File

@@ -12,8 +12,6 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using LedgerProgram = StellaOps.Findings.Ledger.WebService.Program;
namespace StellaOps.Findings.Ledger.Tests.Integration;
/// <summary>
@@ -22,11 +20,11 @@ namespace StellaOps.Findings.Ledger.Tests.Integration;
/// </summary>
[Trait("Category", "Integration")]
[Trait("Sprint", "8200.0012.0004")]
public sealed class ScoringObservabilityTests : IClassFixture<WebApplicationFactory<LedgerProgram>>
public sealed class ScoringObservabilityTests : IClassFixture<FindingsLedgerWebApplicationFactory>
{
private readonly HttpClient _client;
public ScoringObservabilityTests(WebApplicationFactory<LedgerProgram> factory)
public ScoringObservabilityTests(FindingsLedgerWebApplicationFactory factory)
{
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{

View File

@@ -11,8 +11,6 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using LedgerProgram = StellaOps.Findings.Ledger.WebService.Program;
namespace StellaOps.Findings.Ledger.Tests.Integration;
/// <summary>
@@ -20,11 +18,11 @@ namespace StellaOps.Findings.Ledger.Tests.Integration;
/// </summary>
[Trait("Category", "Integration")]
[Trait("Sprint", "8200.0012.0004")]
public sealed class WebhookEndpointsIntegrationTests : IClassFixture<WebApplicationFactory<LedgerProgram>>
public sealed class WebhookEndpointsIntegrationTests : IClassFixture<FindingsLedgerWebApplicationFactory>
{
private readonly HttpClient _client;
public WebhookEndpointsIntegrationTests(WebApplicationFactory<LedgerProgram> factory)
public WebhookEndpointsIntegrationTests(FindingsLedgerWebApplicationFactory factory)
{
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{

View File

@@ -8,3 +8,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
| AUDIT-0343-M | DONE | Revalidated 2026-01-07; maintainability audit for Findings.Ledger.Tests. |
| AUDIT-0343-T | DONE | Revalidated 2026-01-07; test coverage audit for Findings.Ledger.Tests. |
| AUDIT-0343-A | DONE | Waived (test project; revalidated 2026-01-07). |
| LEDGER-TESTS-0001 | DOING | Stabilize Findings Ledger WebService test harness (config/auth + stubs). |