more audit work
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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). |
|
||||
|
||||
Reference in New Issue
Block a user