diff --git a/apps/windows_agent/src/TermRemoteCtl.Agent/Configuration/AgentOptionsValidator.cs b/apps/windows_agent/src/TermRemoteCtl.Agent/Configuration/AgentOptionsValidator.cs index f3ff91e..a8da287 100644 --- a/apps/windows_agent/src/TermRemoteCtl.Agent/Configuration/AgentOptionsValidator.cs +++ b/apps/windows_agent/src/TermRemoteCtl.Agent/Configuration/AgentOptionsValidator.cs @@ -1,3 +1,4 @@ +using System.Net; using Microsoft.Extensions.Options; namespace TermRemoteCtl.Agent.Configuration; @@ -13,6 +14,11 @@ public sealed class AgentOptionsValidator : IValidateOptions failures.Add("Agent:DataRoot must be configured."); } + if (!IsValidBindAddress(options.BindAddress)) + { + failures.Add("Agent:BindAddress must be 'localhost' or an IP address literal."); + } + if (options.HttpsPort is < 1 or > 65535) { failures.Add("Agent:HttpsPort must be between 1 and 65535."); @@ -23,8 +29,28 @@ public sealed class AgentOptionsValidator : IValidateOptions failures.Add("Agent:WebSocketFrameFlushMilliseconds must be positive."); } + if (options.RingBufferLineLimit <= 0) + { + failures.Add("Agent:RingBufferLineLimit must be positive."); + } + return failures.Count > 0 ? ValidateOptionsResult.Fail(failures) : ValidateOptionsResult.Success; } + + private static bool IsValidBindAddress(string? bindAddress) + { + if (string.IsNullOrWhiteSpace(bindAddress)) + { + return false; + } + + if (string.Equals(bindAddress, "localhost", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + return IPAddress.TryParse(bindAddress, out _); + } } diff --git a/apps/windows_agent/tests/TermRemoteCtl.Agent.Tests/Configuration/AgentOptionsPipelineTests.cs b/apps/windows_agent/tests/TermRemoteCtl.Agent.Tests/Configuration/AgentOptionsPipelineTests.cs index ff47ac6..33fc567 100644 --- a/apps/windows_agent/tests/TermRemoteCtl.Agent.Tests/Configuration/AgentOptionsPipelineTests.cs +++ b/apps/windows_agent/tests/TermRemoteCtl.Agent.Tests/Configuration/AgentOptionsPipelineTests.cs @@ -54,6 +54,7 @@ public class AgentOptionsPipelineTests [Theory] [InlineData("0", "33", "HttpsPort")] [InlineData("9443", "0", "WebSocketFrameFlushMilliseconds")] + [InlineData("9443", "33", "RingBufferLineLimit")] public void ResolveOptions_Fails_When_Config_Is_Invalid( string httpsPort, string flushMilliseconds, @@ -64,7 +65,7 @@ public class AgentOptionsPipelineTests ["Agent:BindAddress"] = "127.0.0.1", ["Agent:HttpsPort"] = httpsPort, ["Agent:WebSocketFrameFlushMilliseconds"] = flushMilliseconds, - ["Agent:RingBufferLineLimit"] = "4000" + ["Agent:RingBufferLineLimit"] = expectedFailure == "RingBufferLineLimit" ? "0" : "4000" }); var services = new ServiceCollection(); diff --git a/apps/windows_agent/tests/TermRemoteCtl.Agent.Tests/Configuration/AgentOptionsValidatorTests.cs b/apps/windows_agent/tests/TermRemoteCtl.Agent.Tests/Configuration/AgentOptionsValidatorTests.cs index 533015a..bc6672b 100644 --- a/apps/windows_agent/tests/TermRemoteCtl.Agent.Tests/Configuration/AgentOptionsValidatorTests.cs +++ b/apps/windows_agent/tests/TermRemoteCtl.Agent.Tests/Configuration/AgentOptionsValidatorTests.cs @@ -21,4 +21,26 @@ public class AgentOptionsValidatorTests Assert.True(result.Failed); Assert.Contains(result.Failures, failure => failure.Contains("DataRoot")); } + + [Theory] + [InlineData("")] + [InlineData("not-an-address")] + public void Validate_Fails_When_BindAddress_Is_Invalid(string bindAddress) + { + var options = new AgentOptions + { + DataRoot = "C:\\ProgramData\\TermRemoteCtl", + BindAddress = bindAddress, + HttpsPort = 9443, + WebSocketFrameFlushMilliseconds = 33, + RingBufferLineLimit = 4000 + }; + + var validator = new AgentOptionsValidator(); + + var result = validator.Validate("Agent", options); + + Assert.True(result.Failed); + Assert.Contains(result.Failures, failure => failure.Contains("BindAddress")); + } }