Initial curated itworx-knowledge-hub source from 3b1751d0d9dee551aa6994eee0093704dc334817
This commit is contained in:
commit
ad8ad252a9
825 files changed
+124216
No files matched your search
@@ -0,0 +1,55 @@
|
||||
using System.Collections.Concurrent;
|
||||
using ItWorx.KnowledgeHub.IntegrationTests.Infrastructure;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ItWorx.KnowledgeHub.IntegrationTests.Operations;
|
||||
|
||||
/// <summary>Proves docs/19-observability.md's "Never log ... passwords" rule with a
|
||||
/// real request through the real logging pipeline, not by code review: every log line
|
||||
/// emitted while handling a real login attempt (wrong password, so the flow visits the
|
||||
/// most log-heavy failure path) is captured and asserted to never contain the raw
|
||||
/// password value.</summary>
|
||||
[Collection(PostgresTestGroup.Name)]
|
||||
public sealed class LoginRedactionTests(PostgresContainerFixture postgres) : OwnerSetupTestBase(postgres)
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_log_line_emitted_during_a_login_attempt_contains_the_raw_password()
|
||||
{
|
||||
const string secretPassword = "u3q7VeryUniquePasswordNeverLogged9Zx";
|
||||
var captured = new ConcurrentQueue<string>();
|
||||
|
||||
using var loggingFactory = Factory.WithWebHostBuilder(builder =>
|
||||
builder.ConfigureLogging(logging => logging.AddProvider(new CapturingLoggerProvider(captured))));
|
||||
using var client = loggingFactory.CreateClient();
|
||||
|
||||
// A wrong-password attempt exercises the most log-heavy path (Identity
|
||||
// failure handling, audit event, rate limiter) without needing the real
|
||||
// owner password.
|
||||
await SetupHelper.LoginAsync(client, OwnerEmail, secretPassword);
|
||||
|
||||
Assert.DoesNotContain(captured, line => line.Contains(secretPassword, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private sealed class CapturingLoggerProvider(ConcurrentQueue<string> sink) : ILoggerProvider
|
||||
{
|
||||
public ILogger CreateLogger(string categoryName) => new CapturingLogger(categoryName, sink);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
private sealed class CapturingLogger(string categoryName, ConcurrentQueue<string> sink) : ILogger
|
||||
{
|
||||
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel) => true;
|
||||
|
||||
public void Log<TState>(
|
||||
LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
||||
{
|
||||
sink.Enqueue($"[{categoryName}] {formatter(state, exception)} {exception}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user