Some checks are pending
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
- ASP.NET Core API POST /api/v1/findings with EF Core (Npgsql, snake_case) and a generated initial migration - The hub is the authority on licenses: verifies the signature itself, rejects invalid (401), community/expired past grace (403), revoked (403, re-checked under the lock) and over the instance limit (403) - Full-state reconciliation per instance: new findings inserted, existing updated, missing ones resolved, rule states upserted; idempotent by submission id; late older submissions are recorded but not applied - Serialized per customer with a PostgreSQL advisory lock (found by a concurrency test: parallel first submissions raced on the license row) - Size and schema validation; tests on real PostgreSQL, including the full path agent → queue → hub → PostgreSQL with evidence redaction Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
56 lines
2 KiB
C#
56 lines
2 KiB
C#
using System.Security.Cryptography;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.AspNetCore.Mvc.Testing;
|
|
using SQLInsight.Hub;
|
|
using SQLInsight.Licensing;
|
|
using Testcontainers.PostgreSql;
|
|
|
|
namespace SQLInsight.IntegrationTests;
|
|
|
|
/// <summary>
|
|
/// SQLInsight Hub in-process on a real PostgreSQL, with a test signing key the hub trusts.
|
|
/// </summary>
|
|
public sealed class HubFixture : IAsyncLifetime
|
|
{
|
|
public const string KeyId = "itest";
|
|
|
|
private readonly PostgreSqlContainer _postgres = new PostgreSqlBuilder("postgres:17-alpine").Build();
|
|
private readonly ECDsa _key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
|
|
|
|
public WebApplicationFactory<HubServerOptions> Factory { get; private set; } = null!;
|
|
|
|
public string PublicKey => Convert.ToBase64String(_key.ExportSubjectPublicKeyInfo());
|
|
|
|
public string ConnectionString => _postgres.GetConnectionString();
|
|
|
|
public async Task InitializeAsync()
|
|
{
|
|
await _postgres.StartAsync();
|
|
Factory = new WebApplicationFactory<HubServerOptions>().WithWebHostBuilder(b =>
|
|
{
|
|
b.UseEnvironment("Development");
|
|
b.UseSetting("ConnectionStrings:Hub", ConnectionString);
|
|
b.UseSetting($"SQLInsight:Hub:TrustedKeys:{KeyId}", PublicKey);
|
|
});
|
|
await HubProgram.MigrateAsync(Factory.Services);
|
|
}
|
|
|
|
public string License(string customer, LicensePlan plan = LicensePlan.Professional, int maxInstances = 0, DateTimeOffset? expires = null, string? id = null) =>
|
|
SignedDocument.Sign(new License
|
|
{
|
|
LicenseId = id ?? Guid.NewGuid().ToString("N"),
|
|
Customer = customer,
|
|
Plan = plan,
|
|
IssuedAt = DateTimeOffset.UtcNow.AddDays(-1),
|
|
ExpiresAt = expires ?? DateTimeOffset.UtcNow.AddYears(1),
|
|
MaxInstances = maxInstances,
|
|
KeyId = KeyId,
|
|
}, _key);
|
|
|
|
public async Task DisposeAsync()
|
|
{
|
|
await Factory.DisposeAsync();
|
|
await _postgres.DisposeAsync();
|
|
_key.Dispose();
|
|
}
|
|
}
|