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
@@ -245,7 +245,7 @@ public class SiteLocalDbWiringTests : IDisposable
var tables = TableNames(db);
// One from each Phase 1 schema, then every Phase 2 table.
// One from each Phase 1 schema, then every Phase 2 table plus the site-secrets tables.
Assert.Contains("OperationTracking", tables);
Assert.Contains("site_events", tables);
Assert.Contains("sf_messages", tables);
@@ -254,6 +254,7 @@ public class SiteLocalDbWiringTests : IDisposable
"deployed_configurations", "static_attribute_overrides", "shared_scripts",
"external_systems", "database_connections", "notification_lists",
"data_connection_definitions", "smtp_configurations", "native_alarm_state",
"deployed_secrets", "mirrored_secrets",
})
{
Assert.Contains(table, tables);
@@ -261,19 +262,21 @@ public class SiteLocalDbWiringTests : IDisposable
}
[Fact]
public void Site_LocalDb_RegistersExactlyTheTenReplicatedTables()
public void Site_LocalDb_RegistersExactlyTheElevenReplicatedTables()
{
// The Phase 2 cutover. This is an EXACTLY check rather than a Contains in both
// directions, and both directions are load-bearing.
// The Phase 2 cutover, extended by site-secrets artifact deploy's deployed_secrets.
// This is an EXACTLY check rather than a Contains in both directions, and both
// directions are load-bearing.
//
// Too few: the table silently stops replicating. Storage still works, every other
// test still passes, and the pair just quietly diverges — the failure mode Phase 1
// existed to end.
//
// Too many: notification_lists and smtp_configurations must NOT be here. They are
// permanently empty by design, and registering them would open a standing
// replication channel whose only historical payload was plaintext SMTP passwords.
// A Contains-based test would never catch that.
// Too many: notification_lists, smtp_configurations, and mirrored_secrets must NOT
// be here. notification_lists/smtp_configurations are permanently empty by design
// (their only historical payload was a plaintext SMTP password); mirrored_secrets is
// node-local fact (which names THIS node has mirrored), not site-wide state. A
// Contains-based test would never catch either.
var db = _host.Services.GetRequiredService<ILocalDb>();
Assert.Equal(
@@ -281,8 +284,9 @@ public class SiteLocalDbWiringTests : IDisposable
// Ordinal order: '_' (0x5F) sorts before 'b' (0x62), so
// data_connection_definitions precedes database_connections.
"OperationTracking", "data_connection_definitions", "database_connections",
"deployed_configurations", "external_systems", "native_alarm_state",
"sf_messages", "shared_scripts", "site_events", "static_attribute_overrides",
"deployed_configurations", "deployed_secrets", "external_systems",
"native_alarm_state", "sf_messages", "shared_scripts", "site_events",
"static_attribute_overrides",
],
db.ReplicatedTables.Keys.OrderBy(k => k, StringComparer.Ordinal).ToArray());
}
@@ -300,6 +304,17 @@ public class SiteLocalDbWiringTests : IDisposable
Assert.DoesNotContain("smtp_configurations", db.ReplicatedTables.Keys);
}
[Fact]
public void Site_LocalDb_DoesNotReplicateTheNodeLocalMirroredSecretsLedger()
{
// mirrored_secrets exists (SiteStorageSchema creates it) but must never be captured:
// it records which names THIS node has mirrored into its own secret store, which is
// per-node fact, not site-wide state — see SiteLocalDbSetup.ReplicatedTables.
var db = _host.Services.GetRequiredService<ILocalDb>();
Assert.DoesNotContain("mirrored_secrets", db.ReplicatedTables.Keys);
}
[Fact]
public void Site_LocalDb_ReplicatedPhase2TablesHaveTheirExpectedPrimaryKeys()
{
@@ -318,6 +333,7 @@ public class SiteLocalDbWiringTests : IDisposable
Assert.Equal(
["instance_unique_name", "source_canonical_name", "source_reference"],
db.ReplicatedTables["native_alarm_state"].PkColumns);
Assert.Equal(["name"], db.ReplicatedTables["deployed_secrets"].PkColumns);
}
private static HashSet<string> TableNames(ILocalDb db)