Some checks are pending
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:2019-latest) (push) Blocked by required conditions
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
Rule packs (support dates and newest CU per release) are published in a signed feed and hot-loaded without a restart; the verified pack is reloaded at startup. New versions are announced (Notify) or downloaded and staged by the unprivileged agent (Automatic), and installed by a privileged apply-update task that re-verifies signature and hash in an admin-only folder, keeps appsettings/web.config, health-checks the services and rolls back on failure. Stable and preview channels, manifest expiry and rollback protection, https or folder/share feeds for offline sites. Vendor tool gains rulepack and publish; the Hub can serve the feed; the web UI gets a System page with update, rule pack, license and exactly what is sent to the Hub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
60 lines
2.3 KiB
C#
60 lines
2.3 KiB
C#
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using SQLInsight.Core.Instances;
|
|
|
|
namespace SQLInsight.Rules.Lifecycle;
|
|
|
|
public sealed record SupportLifecycle(SqlServerRelease Release, DateOnly? MainstreamEnd, DateOnly? ExtendedEnd);
|
|
|
|
/// <summary>
|
|
/// Microsoft's support dates per SQL Server release. Shipped as data so it can be updated with the rule pack.
|
|
/// </summary>
|
|
public sealed class SupportLifecycleCatalog
|
|
{
|
|
private const string ResourceName = "SQLInsight.Rules.support-lifecycle.json";
|
|
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
PropertyNameCaseInsensitive = true,
|
|
Converters = { new JsonStringEnumConverter() },
|
|
};
|
|
|
|
private readonly Dictionary<SqlServerRelease, SupportLifecycle> _entries;
|
|
|
|
public SupportLifecycleCatalog(IEnumerable<SupportLifecycle> entries)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(entries);
|
|
_entries = entries.ToDictionary(e => e.Release);
|
|
}
|
|
|
|
public static SupportLifecycleCatalog LoadEmbedded()
|
|
{
|
|
using var stream = typeof(SupportLifecycleCatalog).Assembly.GetManifestResourceStream(ResourceName)
|
|
?? throw new InvalidOperationException($"Embedded resource '{ResourceName}' is missing.");
|
|
return From(JsonSerializer.Deserialize<CatalogDocument>(stream, JsonOptions));
|
|
}
|
|
|
|
/// <summary>Reads the lifecycle section of a rule pack. Throws <see cref="InvalidDataException"/> if it is malformed.</summary>
|
|
public static SupportLifecycleCatalog FromJson(JsonElement element) => From(element.Deserialize<CatalogDocument>(JsonOptions));
|
|
|
|
private static SupportLifecycleCatalog From(CatalogDocument? document)
|
|
{
|
|
if (document?.Releases is not { Count: > 0 } releases)
|
|
{
|
|
throw new InvalidDataException("The support lifecycle catalog is empty.");
|
|
}
|
|
|
|
try
|
|
{
|
|
return new SupportLifecycleCatalog(releases);
|
|
}
|
|
catch (ArgumentException ex)
|
|
{
|
|
throw new InvalidDataException("The support lifecycle catalog is invalid: " + ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
public SupportLifecycle? Find(SqlServerRelease release) => _entries.GetValueOrDefault(release);
|
|
|
|
private sealed record CatalogDocument(IReadOnlyList<SupportLifecycle> Releases);
|
|
}
|