dd0a846b64
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
42 lines
1.9 KiB
C#
42 lines
1.9 KiB
C#
using Akka.Configuration;
|
|
|
|
namespace ZB.MOM.WW.Secrets.Replicator.AkkaDotNet;
|
|
|
|
/// <summary>
|
|
/// Akka configuration this package contributes.
|
|
/// </summary>
|
|
public static class AkkaSecretsReplication
|
|
{
|
|
/// <summary>
|
|
/// HOCON binding the secret-replication wire protocol to
|
|
/// <see cref="SecretReplicationSerializer"/>. Merge it into the application's Akka
|
|
/// configuration when creating the <c>ActorSystem</c>:
|
|
/// <code>
|
|
/// Config config = AkkaSecretsReplication.SerializationConfig
|
|
/// .WithFallback(myAppConfig);
|
|
/// ActorSystem.Create("my-system", config);
|
|
/// </code>
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Optional — the protocol DTOs round-trip under Akka's default JSON serializer without it — but
|
|
/// recommended, because it makes the serializer carrying secret ciphertext an explicit choice
|
|
/// rather than an inherited default, and pins the manifest strings that a future protocol
|
|
/// version would bump.
|
|
/// </remarks>
|
|
public static Config SerializationConfig { get; } = ConfigurationFactory.ParseString($$"""
|
|
akka.actor {
|
|
serializers {
|
|
zb-secrets-replication = "{{typeof(SecretReplicationSerializer).AssemblyQualifiedName}}"
|
|
}
|
|
serialization-bindings {
|
|
"ZB.MOM.WW.Secrets.Replicator.AkkaDotNet.Protocol.SecretRowsMessage, ZB.MOM.WW.Secrets.Replicator.AkkaDotNet" = zb-secrets-replication
|
|
"ZB.MOM.WW.Secrets.Replicator.AkkaDotNet.Protocol.SecretManifestAnnounce, ZB.MOM.WW.Secrets.Replicator.AkkaDotNet" = zb-secrets-replication
|
|
"ZB.MOM.WW.Secrets.Replicator.AkkaDotNet.Protocol.SecretPullRequest, ZB.MOM.WW.Secrets.Replicator.AkkaDotNet" = zb-secrets-replication
|
|
}
|
|
serialization-identifiers {
|
|
"{{typeof(SecretReplicationSerializer).AssemblyQualifiedName}}" = {{SecretReplicationSerializer.SerializerId}}
|
|
}
|
|
}
|
|
""");
|
|
}
|