fix(configuration-database): resolve ConfigurationDatabase-002..007 — remove hardcoded sa creds, fail-fast no-arg DI, encrypt secret columns, resilient audit serialization

This commit is contained in:
Joseph Doherty
2026-05-16 21:11:24 -04:00
parent 8fc04d43c2
commit 0c82ffcbe6
17 changed files with 2029 additions and 40 deletions

View File

@@ -124,4 +124,35 @@ public class AuditServiceTests : IDisposable
Assert.DoesNotContain(methods, m => m.Name.Contains("Update", StringComparison.OrdinalIgnoreCase));
Assert.DoesNotContain(methods, m => m.Name.Contains("Delete", StringComparison.OrdinalIgnoreCase));
}
// Self-referential POCO used to reproduce a reference cycle in afterState.
private sealed class CyclicNode
{
public string Name { get; set; } = "node";
public CyclicNode? Self { get; set; }
}
[Fact]
public async Task LogAsync_AfterStateWithReferenceCycle_DoesNotThrow_AndDoesNotRollBackOperation()
{
// Regression guard for ConfigurationDatabase-007: serializing an afterState
// object that contains a reference cycle must not throw a JsonException —
// that would roll back the entire business operation it is auditing.
var node = new CyclicNode();
node.Self = node; // reference cycle
var template = new Template("CyclicAuditTemplate");
_context.Templates.Add(template);
// Must not throw.
await _auditService.LogAsync("admin", "Create", "Template", "1", "CyclicAuditTemplate", node);
// The audited business operation must still commit successfully.
await _context.SaveChangesAsync();
var audit = await _context.AuditLogEntries.SingleAsync();
Assert.NotNull(audit.AfterStateJson);
Assert.Contains("node", audit.AfterStateJson);
Assert.Single(await _context.Templates.Where(t => t.Name == "CyclicAuditTemplate").ToListAsync());
}
}