Files
scadaproj/ZB.MOM.WW.Secrets/src/ZB.MOM.WW.Secrets.Abstractions/ISecretsStoreMigrator.cs
T
Joseph Doherty dd0a846b64 feat(secrets): cluster replication via SQL Server and Akka.NET (G-7, 0.2.0)
Secrets were per-node SQLite, so a secret written on one node was invisible to
the rest of a cluster. G-7's design resolved the "shared SQL store vs Akka
replicator" fork to build only the former; both are built here so the choice is
a deployment decision (availability vs partition tolerance) rather than a
library limitation.

Two new packages — ZB.MOM.WW.Secrets.Replicator.SqlServer (shared store, plus a
local-store-with-hub mode) and .Replicator.AkkaDotNet (peer-to-peer over
distributed pub/sub). Core gains ISecretsStoreMigrator, one shared
SecretLastWriterWins predicate so no two stores can disagree on a tie, the
transport-agnostic reconciler, and ReplicatingSecretStore — which closes a real
gap: nothing had ever called ISecretReplicator.PublishAsync, so the seam was
inert and local writes would not have propagated at all.

Verified 182 pass / 1 skip / 0 warnings, including 15 live tests against a real
SQL Server 2022 (the SQLite suite ported case-for-case, so any behavioural
divergence between the stores fails) and a 9-test in-process 2-node Akka
cluster over real remoting. A post-build review caught six defects, all fixed
and now covered: both replication modes could not resolve from the container
(no test had built one), an unbounded fetch that broke past SQL Server's
2100-parameter cap, a poison row that aborted the rest of its batch forever,
Enum.Parse on peer input that could restart the actor in a loop, null crypto
blobs crossing the trust boundary, and a silently dropped pull-read failure.

Packed at 0.2.0 and vulnerability-scanned clean; not yet published to the feed.

Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-18 04:08:23 -04:00

23 lines
1.2 KiB
C#

namespace ZB.MOM.WW.Secrets.Abstractions;
/// <summary>
/// Provisions the schema backing an <see cref="ISecretStore"/>. Implementations are idempotent —
/// running a migration repeatedly is safe — and refuse to run against a store whose on-disk schema
/// version is <em>newer</em> than the build supports, rather than silently downgrading it.
/// </summary>
/// <remarks>
/// This seam exists so the startup migration hosted service and the CLI stay store-agnostic: the
/// SQLite store, the shared SQL-Server store, and any future provider are all provisioned through
/// the same call, and swapping the store never touches the migration wiring.
/// </remarks>
public interface ISecretsStoreMigrator
{
/// <summary>Creates or updates the secret-store schema to the version this build supports.</summary>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A task that completes when the schema is at the supported version.</returns>
/// <exception cref="SecretStoreMigrationException">
/// The store's schema version is newer than this build supports.
/// </exception>
Task MigrateAsync(CancellationToken cancellationToken);
}