From 9b4890326e85307a42104b93b30860a7eabedca5 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 13 Jul 2026 10:05:31 -0400 Subject: [PATCH] =?UTF-8?q?fix(transport):=20validate=20MaxConcurrentImpor?= =?UTF-8?q?tSessions=20at=20startup=20=E2=80=94=20a=20zero=20cap=20no=20lo?= =?UTF-8?q?nger=20bricks=20imports=20silently=20(plan=20R2-05=20T8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TransportOptionsValidator.cs | 4 ++++ .../TransportOptionsValidatorTests.cs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/ZB.MOM.WW.ScadaBridge.Transport/TransportOptionsValidator.cs b/src/ZB.MOM.WW.ScadaBridge.Transport/TransportOptionsValidator.cs index d5dd9eb5..43799b13 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Transport/TransportOptionsValidator.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Transport/TransportOptionsValidator.cs @@ -48,6 +48,10 @@ public sealed class TransportOptionsValidator : OptionsValidatorBase 0, + $"ScadaBridge:Transport:MaxConcurrentImportSessions must be positive " + + $"(was {options.MaxConcurrentImportSessions}); a zero/negative cap rejects every import session forever."); + builder.RequireThat(options.MaxUnlockAttemptsPerIpPerHour > 0, $"ScadaBridge:Transport:MaxUnlockAttemptsPerIpPerHour must be positive " + $"(was {options.MaxUnlockAttemptsPerIpPerHour}); it caps unlock attempts per IP address per hour."); diff --git a/tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/TransportOptionsValidatorTests.cs b/tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/TransportOptionsValidatorTests.cs index 1c40c78c..47a3a213 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/TransportOptionsValidatorTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/TransportOptionsValidatorTests.cs @@ -38,6 +38,22 @@ public class TransportOptionsValidatorTests Assert.Contains("MaxBundleSizeMb", result.FailureMessage); } + [Fact] + public void ZeroMaxConcurrentImportSessions_IsRejected() + { + var result = Validate(new TransportOptions { MaxConcurrentImportSessions = 0 }); + Assert.True(result.Failed); + Assert.Contains("MaxConcurrentImportSessions", result.FailureMessage); // FAILS today: validates clean + } + + [Fact] + public void NegativeMaxConcurrentImportSessions_IsRejected() + { + var result = Validate(new TransportOptions { MaxConcurrentImportSessions = -1 }); + Assert.True(result.Failed); + Assert.Contains("MaxConcurrentImportSessions", result.FailureMessage); + } + [Fact] public void ZeroPbkdf2Iterations_IsRejected() {