Files
ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.Host.Tests/BundleSigningPolicyHealthCheckTests.cs
T
Joseph Doherty 559e02f5c8 feat(transport): production-boundary signing advisory, secret-key proof, runbook (#110)
Owner decisions on #110: one signing key per environment; TrustedKeys stay hand-edited;
Signing:ProductionBoundary (new, default off) logs a startup warning and reports a Degraded
bundle-signing-policy /health/ready entry while RequireSignedBundles is off; the private key
is read via ${secret:} (proved end to end, never logged); cluster pull decided not to be
built; differential deletions stay deferred. Adds docs/operations/bundle-signing-runbook.md.

Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
2026-11-09 22:50:18 -05:00

36 lines
1.4 KiB
C#

using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.ScadaBridge.Host.Health;
using ZB.MOM.WW.ScadaBridge.Transport;
namespace ZB.MOM.WW.ScadaBridge.Host.Tests;
/// <summary>ScadaBridge#110: the bundle-signing-policy readiness entry.</summary>
public sealed class BundleSigningPolicyHealthCheckTests
{
private sealed class FixedMonitor(TransportOptions o) : IOptionsMonitor<TransportOptions>
{
public TransportOptions CurrentValue => o;
public TransportOptions Get(string? name) => o;
public IDisposable? OnChange(Action<TransportOptions, string?> listener) => null;
}
/// <summary>Degraded only when a production-boundary cluster accepts unsigned bundles.</summary>
[Theory]
[InlineData(true, false, HealthStatus.Degraded)]
[InlineData(true, true, HealthStatus.Healthy)]
[InlineData(false, false, HealthStatus.Healthy)]
public async Task Status_follows_policy(bool boundary, bool require, HealthStatus expected)
{
var o = new TransportOptions();
o.Signing.ProductionBoundary = boundary;
o.Signing.RequireSignedBundles = require;
var result = await new BundleSigningPolicyHealthCheck(new FixedMonitor(o))
.CheckHealthAsync(new HealthCheckContext());
Assert.Equal(expected, result.Status);
Assert.Equal(boundary, result.Data["productionBoundary"]);
}
}