fix(deployment): pending-updates tick uses a slim instance projection, hash-only flatten, one untracked mismatch snapshot read and a per-tick secret lookup memo (review 2026-10-21 04/P2)

This commit is contained in:
Joseph Doherty
2026-10-22 06:39:45 -04:00
parent 971a9886b8
commit df67fabe68
17 changed files with 443 additions and 128 deletions
@@ -745,6 +745,40 @@ public class ArtifactDeploymentServiceTests : TestKit
Assert.DoesNotContain(capturingLogger.Messages, m => m.Contains(ciphertextHex, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// review 2026-10-21 04/P2: computing current artifact hashes for N sites that reference the
/// same secret reads it from the central store ONCE per evaluation, not once per site — and
/// both sites still hash identically to their own uncached computation.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ComputeCurrentArtifactHashes_SharedSecret_IsReadFromTheStoreOncePerEvaluation()
{
var siteA = new Site("Site A", "site-a") { Id = 1 };
var siteB = new Site("Site B", "site-b") { Id = 2 };
foreach (var id in new[] { 1, 2 })
{
_siteRepo.GetDataConnectionsBySiteIdAsync(id, Arg.Any<CancellationToken>())
.Returns(new List<DataConnection>
{
new($"GW{id}", "MxGateway", id) { PrimaryConfiguration = """{"ApiKey":"secret:shared-key"}""" }
});
}
_secretStore.GetAsync(Arg.Is<SecretName>(n => n.Value == "shared-key"), Arg.Any<CancellationToken>())
.Returns(Task.FromResult<StoredSecret?>(SecretRow("shared-key", 3)));
var service = CreateService();
var hashes = await service.ComputeCurrentArtifactHashesAsync([siteA, siteB]);
Assert.Equal(2, hashes.Count);
await _secretStore.Received(1).GetAsync(
Arg.Is<SecretName>(n => n.Value == "shared-key"), Arg.Any<CancellationToken>());
// Memoisation must not change the answer.
var single = await service.ComputeCurrentArtifactHashesAsync([siteB]);
Assert.Equal(single[2], hashes[2]);
}
// ── Stamp gating on secret application + DeploySiteSecrets audit row ──
/// <summary>Verifies that an old site that reports no applied secrets fails and is not stamped when secrets were shipped.</summary>