sqlinsight-pro/src/SQLInsight.Repository/InsightRepository.Updates.cs
Claude 3121b598f9
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
Fase 3: signed updates of rule packs and the application
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
2026-09-29 09:19:41 +00:00

52 lines
3 KiB
C#

using Dapper;
namespace SQLInsight.Repository;
public sealed record UpdateStatusRow
{
public string? Feed { get; init; }
public string Channel { get; init; } = "stable";
public string Mode { get; init; } = "Notify";
public bool RulePacks { get; init; }
public string InstalledVersion { get; init; } = string.Empty;
public string RulePackVersion { get; init; } = string.Empty;
public string RulePackSource { get; init; } = string.Empty;
public string? AvailableVersion { get; init; }
public bool AvailableSecurity { get; init; }
public string? AvailableNotesUrl { get; init; }
public string? StagedVersion { get; init; }
public DateTime? LastCheckAt { get; init; }
public string? LastError { get; init; }
public string? LastResultOutcome { get; init; }
public string? LastResultMessage { get; init; }
public DateTime? LastResultAt { get; init; }
public DateTime UpdatedAt { get; init; }
}
public sealed partial class InsightRepository
{
public async Task SaveUpdateStatusAsync(UpdateStatusRow status, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(status);
await using var connection = await OpenAsync(cancellationToken).ConfigureAwait(false);
await connection.ExecuteAsync("""
MERGE insight.UpdateStatus AS t
USING (SELECT 1 AS Id) AS s ON t.Id = s.Id
WHEN MATCHED THEN UPDATE SET Feed = @Feed, Channel = @Channel, Mode = @Mode, RulePacks = @RulePacks, InstalledVersion = @InstalledVersion,
RulePackVersion = @RulePackVersion, RulePackSource = @RulePackSource, AvailableVersion = @AvailableVersion,
AvailableSecurity = @AvailableSecurity, AvailableNotesUrl = @AvailableNotesUrl, StagedVersion = @StagedVersion,
LastCheckAt = @LastCheckAt, LastError = @LastError, LastResultOutcome = @LastResultOutcome,
LastResultMessage = @LastResultMessage, LastResultAt = @LastResultAt, UpdatedAt = @UpdatedAt
WHEN NOT MATCHED THEN INSERT (Id, Feed, Channel, Mode, RulePacks, InstalledVersion, RulePackVersion, RulePackSource, AvailableVersion,
AvailableSecurity, AvailableNotesUrl, StagedVersion, LastCheckAt, LastError, LastResultOutcome, LastResultMessage, LastResultAt, UpdatedAt)
VALUES (1, @Feed, @Channel, @Mode, @RulePacks, @InstalledVersion, @RulePackVersion, @RulePackSource, @AvailableVersion,
@AvailableSecurity, @AvailableNotesUrl, @StagedVersion, @LastCheckAt, @LastError, @LastResultOutcome, @LastResultMessage, @LastResultAt, @UpdatedAt);
""", status).ConfigureAwait(false);
}
public async Task<UpdateStatusRow?> GetUpdateStatusAsync(CancellationToken cancellationToken = default)
{
await using var connection = await OpenAsync(cancellationToken).ConfigureAwait(false);
return await connection.QuerySingleOrDefaultAsync<UpdateStatusRow>("SELECT * FROM insight.UpdateStatus WHERE Id = 1;").ConfigureAwait(false);
}
}