Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
- SQLInsight.Licensing: ECDSA P-256 signed documents (SQLI1.payload.sig), licenses with plan, expiry, instance count and key id for rotation; 30-day grace; invalid or missing licenses are states, never errors, and never stop monitoring (a license only adds hub sync and support) - Trusted public keys are embedded; the source ships with none, so a published key can never mint licenses. The vendor adds its own. - tools/SQLInsight.LicenseTool: keygen, issue, verify - *.private.pem ignored by git Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
125 lines
4.3 KiB
C#
125 lines
4.3 KiB
C#
using System.Security.Cryptography;
|
|
|
|
namespace SQLInsight.Licensing.Tests;
|
|
|
|
public class LicenseTests
|
|
{
|
|
private static readonly DateTimeOffset Now = new(2026, 9, 29, 12, 0, 0, TimeSpan.Zero);
|
|
|
|
private sealed class FixedTime(DateTimeOffset now) : TimeProvider
|
|
{
|
|
public override DateTimeOffset GetUtcNow() => now;
|
|
}
|
|
|
|
private static (ECDsa Key, TrustedKeys Trusted) NewKey(string kid = "test1")
|
|
{
|
|
var key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
|
|
return (key, new TrustedKeys([KeyValuePair.Create(kid, Convert.ToBase64String(key.ExportSubjectPublicKeyInfo()))]));
|
|
}
|
|
|
|
private static License Sample(DateTimeOffset expires, LicensePlan plan = LicensePlan.Professional, string kid = "test1") => new()
|
|
{
|
|
LicenseId = "lic-1", Customer = "Kunde A/S", Plan = plan, IssuedAt = Now.AddDays(-10), ExpiresAt = expires, MaxInstances = 5, KeyId = kid,
|
|
};
|
|
|
|
private static LicenseStatus Check(string text, TrustedKeys keys, DateTimeOffset? now = null) => new LicenseVerifier(keys, new FixedTime(now ?? Now)).Check(text);
|
|
|
|
[Fact]
|
|
public void Valid_license_round_trips()
|
|
{
|
|
var (key, trusted) = NewKey();
|
|
var text = SignedDocument.Sign(Sample(Now.AddYears(1)), key);
|
|
|
|
var status = Check(text, trusted);
|
|
|
|
Assert.StartsWith("SQLI1.", text, StringComparison.Ordinal);
|
|
Assert.Equal(LicenseState.Valid, status.State);
|
|
Assert.Equal("Kunde A/S", status.License!.Customer);
|
|
Assert.True(status.AllowsFindingsSync);
|
|
}
|
|
|
|
[Fact]
|
|
public void No_license_is_community_and_not_an_error()
|
|
{
|
|
var status = Check("", NewKey().Trusted);
|
|
|
|
Assert.Equal(LicenseState.None, status.State);
|
|
Assert.False(status.AllowsFindingsSync);
|
|
}
|
|
|
|
[Fact]
|
|
public void Tampered_payload_is_invalid()
|
|
{
|
|
var (key, trusted) = NewKey();
|
|
var parts = SignedDocument.Sign(Sample(Now.AddYears(1)), key).Split('.');
|
|
var forged = SignedDocument.Sign(Sample(Now.AddYears(10), LicensePlan.Enterprise), ECDsa.Create(ECCurve.NamedCurves.nistP256)).Split('.');
|
|
|
|
// Enterprise payload with the original, genuine signature.
|
|
Assert.Equal(LicenseState.Invalid, Check($"{parts[0]}.{forged[1]}.{parts[2]}", trusted).State);
|
|
}
|
|
|
|
[Fact]
|
|
public void License_signed_with_an_untrusted_key_is_invalid()
|
|
{
|
|
var (_, trusted) = NewKey();
|
|
var (other, _) = NewKey();
|
|
|
|
Assert.Equal(LicenseState.Invalid, Check(SignedDocument.Sign(Sample(Now.AddYears(1)), other), trusted).State);
|
|
}
|
|
|
|
[Fact]
|
|
public void Unknown_key_id_is_invalid()
|
|
{
|
|
var (key, trusted) = NewKey("test1");
|
|
|
|
Assert.Equal(LicenseState.Invalid, Check(SignedDocument.Sign(Sample(Now.AddYears(1), kid: "other"), key), trusted).State);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("garbage")]
|
|
[InlineData("SQLI1.x.y")]
|
|
[InlineData("SQLI1.@@@.###")]
|
|
[InlineData("SQLI2.a.b")]
|
|
public void Garbage_is_invalid_not_an_exception(string text)
|
|
{
|
|
Assert.Equal(LicenseState.Invalid, Check(text, NewKey().Trusted).State);
|
|
}
|
|
|
|
[Fact]
|
|
public void Expired_license_keeps_syncing_during_grace_then_stops()
|
|
{
|
|
var (key, trusted) = NewKey();
|
|
var text = SignedDocument.Sign(Sample(Now), key);
|
|
|
|
var grace = Check(text, trusted, Now.AddDays(10));
|
|
var expired = Check(text, trusted, Now.AddDays(31));
|
|
|
|
Assert.Equal(LicenseState.ExpiredInGrace, grace.State);
|
|
Assert.True(grace.AllowsFindingsSync);
|
|
Assert.Equal(LicenseState.Expired, expired.State);
|
|
Assert.False(expired.AllowsFindingsSync);
|
|
}
|
|
|
|
[Fact]
|
|
public void Community_plan_does_not_include_sync()
|
|
{
|
|
var (key, trusted) = NewKey();
|
|
|
|
Assert.False(Check(SignedDocument.Sign(Sample(Now.AddYears(1), LicensePlan.Community), key), trusted).AllowsFindingsSync);
|
|
}
|
|
|
|
[Fact]
|
|
public void Plans()
|
|
{
|
|
Assert.True(Sample(Now, LicensePlan.Enterprise).IncludesPhoneSupport);
|
|
Assert.False(Sample(Now, LicensePlan.Professional).IncludesPhoneSupport);
|
|
Assert.True(Sample(Now, LicensePlan.Professional).IncludesPrioritySupport);
|
|
}
|
|
|
|
[Fact]
|
|
public void Source_ships_without_trusted_keys()
|
|
{
|
|
// The vendor adds its public key before a release; a published test key would let anyone mint licenses.
|
|
Assert.Equal(0, TrustedKeys.Embedded().Count);
|
|
}
|
|
}
|