feat(site): deployed_secrets (LocalDb-replicated ciphertext) + node-local mirrored_secrets ledger

This commit is contained in:
Joseph Doherty
2026-09-28 18:36:49 -04:00
parent 437b02a43c
commit a35ee663c8
8 changed files with 662 additions and 22 deletions
@@ -48,14 +48,27 @@ namespace ZB.MOM.WW.ScadaBridge.Host;
public static class SiteLocalDbSetup
{
/// <summary>
/// The ten tables that participate in replication — registered when this node has a peer,
/// The eleven tables that participate in replication — registered when this node has a peer,
/// and deregistered (stale triggers dropped) when it does not.
/// </summary>
/// <remarks>
/// <para>
/// <c>notification_lists</c> and <c>smtp_configurations</c> are created by the schema but
/// deliberately absent here; see the rationale in <see cref="OnReady"/>. The list is shared by
/// both branches on purpose: a table added to one and not the other would either register
/// without ever being cleaned up, or be cleaned up on a node that never registered it.
/// </para>
/// <para>
/// <c>deployed_secrets</c> (ciphertext-only, see <c>SecretArtifact</c>) is the eleventh
/// entry, added for site-secrets artifact deploy. It has an explicit primary key
/// (<c>name</c>) and no FK, so it registers like any other member of this list.
/// <c>mirrored_secrets</c> is deliberately NOT here, for the same reason
/// <c>notification_lists</c>/<c>smtp_configurations</c> are not: which names THIS node has
/// mirrored into its own local secret store is per-node fact, not site-wide state — the
/// two site nodes can be at different points in mirroring the same replicated
/// <c>deployed_secrets</c> row, and replicating the ledger would make one node's progress
/// masquerade as the other's.
/// </para>
/// </remarks>
internal static readonly string[] ReplicatedTables =
[
@@ -69,6 +82,7 @@ public static class SiteLocalDbSetup
"database_connections",
"data_connection_definitions",
"native_alarm_state",
"deployed_secrets",
];
/// <summary>
@@ -122,11 +136,12 @@ public static class SiteLocalDbSetup
//
// The PER-TABLE loop is load-bearing as of LocalDb 0.3.0, not just tidy. The snapshot
// flag baselining raises is now per-table, and it is raised by the call that actually
// seeded something — so adding an ELEVENTH table to ReplicatedTables on an already
// replicating site now streams a snapshot of that one table, where through 0.2.x the
// flag was a single per-database bit and the same edit re-streamed all eleven in full,
// in both directions. Nothing about the first boot changes: enabling replication on a
// site that has been running without it seeds all ten at once, the flagged set is
// seeded something — so site-secrets artifact deploy adding deployed_secrets as an
// ELEVENTH entry to ReplicatedTables on an already-replicating site streams a
// snapshot of only that one table, where through 0.2.x the flag was a single
// per-database bit and the same edit would have re-streamed all eleven in full, in
// both directions. Nothing about the first boot changes: enabling replication on a
// site that has been running without it seeds all eleven at once, the flagged set is
// therefore every registered table, and the library sends that as an ordinary full
// snapshot. A hypothetical "register the whole list in one call" API would silently
// give the coarse behaviour back.