From a96431d1e6efcc3b611c129efd829c2eff7f2cc9 Mon Sep 17 00:00:00 2001 From: Sellakumaran Kanagarathnam Date: Fri, 13 Feb 2026 16:25:23 -0800 Subject: [PATCH 1/2] fix(setup): trim trailing hyphens from endpoint names to comply with Azure Bot Service naming rules When long hostnames (e.g., ngrok free domains) are truncated to 42 characters for Azure Bot Service, they can end with trailing hyphens. Azure Bot Service rejects such names with InternalServerError. Changes: - EndpointHelper.GetEndpointName() now trims trailing hyphens after truncation - Added input validation for null/whitespace endpoint names - Fixed CleanupCommand to display truncated endpoint name in preview - Added comprehensive test coverage (12 tests) including edge cases Fixes endpoint registration failures for users with long messaging endpoint URLs. Co-Authored-By: Claude Sonnet 4.5 --- .../Commands/CleanupCommand.cs | 5 +- .../Services/Helpers/EndpointHelper.cs | 24 +++- .../Services/Helpers/EndpointHelperTests.cs | 126 ++++++++++++++++++ 3 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/Helpers/EndpointHelperTests.cs diff --git a/src/Microsoft.Agents.A365.DevTools.Cli/Commands/CleanupCommand.cs b/src/Microsoft.Agents.A365.DevTools.Cli/Commands/CleanupCommand.cs index c66c87f6..8b4c3bd4 100644 --- a/src/Microsoft.Agents.A365.DevTools.Cli/Commands/CleanupCommand.cs +++ b/src/Microsoft.Agents.A365.DevTools.Cli/Commands/CleanupCommand.cs @@ -776,11 +776,14 @@ private static async Task ExecuteEndpointOnlyCleanupAsync( return; } + // Get the actual endpoint name that will be used for deletion (truncated to 42 chars) + var endpointName = EndpointHelper.GetEndpointName(config.BotName); + logger.LogInformation(""); logger.LogInformation("Endpoint Cleanup Preview:"); logger.LogInformation("============================"); logger.LogInformation("Will delete messaging endpoint:"); - logger.LogInformation(" Endpoint Name: {BotName}", config.BotName); + logger.LogInformation(" Endpoint Name: {EndpointName}", endpointName); logger.LogInformation(" Location: {Location}", config.Location); logger.LogInformation(""); diff --git a/src/Microsoft.Agents.A365.DevTools.Cli/Services/Helpers/EndpointHelper.cs b/src/Microsoft.Agents.A365.DevTools.Cli/Services/Helpers/EndpointHelper.cs index 7b8fde08..0fe6788d 100644 --- a/src/Microsoft.Agents.A365.DevTools.Cli/Services/Helpers/EndpointHelper.cs +++ b/src/Microsoft.Agents.A365.DevTools.Cli/Services/Helpers/EndpointHelper.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using Microsoft.Agents.A365.DevTools.Cli.Constants; +using Microsoft.Agents.A365.DevTools.Cli.Exceptions; namespace Microsoft.Agents.A365.DevTools.Cli.Services.Helpers; @@ -9,9 +10,30 @@ public static class EndpointHelper { public static string GetEndpointName(string name) { - return name.Length > 42 + // Validate input + if (string.IsNullOrWhiteSpace(name)) + { + throw new SetupValidationException("Endpoint name cannot be null or whitespace."); + } + + // Truncate to 42 characters (Azure Bot Service maximum) + var truncated = name.Length > 42 ? name.Substring(0, 42) : name; + + // Trim trailing hyphens to comply with Azure Bot Service naming rules + // Azure Bot Service does not allow bot names ending with hyphens + truncated = truncated.TrimEnd('-'); + + // Validate minimum length after trimming + if (truncated.Length < 4) + { + throw new SetupValidationException( + $"Endpoint name '{name}' becomes too short after processing (minimum 4 characters required). " + + "Please use a shorter hostname or provide a custom endpoint name."); + } + + return truncated; } /// diff --git a/src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/Helpers/EndpointHelperTests.cs b/src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/Helpers/EndpointHelperTests.cs new file mode 100644 index 00000000..94acba4e --- /dev/null +++ b/src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/Helpers/EndpointHelperTests.cs @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using FluentAssertions; +using Microsoft.Agents.A365.DevTools.Cli.Exceptions; +using Microsoft.Agents.A365.DevTools.Cli.Services.Helpers; +using Xunit; + +namespace Microsoft.Agents.A365.DevTools.Cli.Tests.Services.Helpers; + +public class EndpointHelperTests +{ + [Fact] + public void GetEndpointName_WhenNameIsUnder42Chars_ReturnsOriginalName() + { + // Arrange + var shortName = "my-endpoint"; + + // Act + var result = EndpointHelper.GetEndpointName(shortName); + + // Assert + result.Should().Be("my-endpoint"); + } + + [Fact] + public void GetEndpointName_WhenNameIsExactly42Chars_ReturnsOriginalName() + { + // Arrange + var exactName = "twelve345678901234567890123456789012345678"; // 42 chars + + // Act + var result = EndpointHelper.GetEndpointName(exactName); + + // Assert + result.Should().Be(exactName); + result.Length.Should().Be(42); + } + + [Fact] + public void GetEndpointName_WhenNameOver42Chars_TruncatesTo42Chars() + { + // Arrange + var longName = "this-is-a-very-long-endpoint-name-that-exceeds-the-limit-of-42-characters"; + + // Act + var result = EndpointHelper.GetEndpointName(longName); + + // Assert + result.Length.Should().Be(42); + } + + [Fact] + public void GetEndpointName_WhenTruncationEndsWithHyphen_ShouldTrimTrailingHyphen() + { + // Arrange - Simulates ngrok free domain scenario + // Original: distressingly-gnathonic-alonzo.ngrok-free.app + // After conversion: distressingly-gnathonic-alonzo-ngrok-free-app-endpoint + var longNameEndingWithHyphen = "distressingly-gnathonic-alonzo-ngrok-free-app-endpoint"; // 54 chars + + // Act + var result = EndpointHelper.GetEndpointName(longNameEndingWithHyphen); + + // Assert + result.Should().Be("distressingly-gnathonic-alonzo-ngrok-free", "should truncate to 42 chars and trim trailing hyphen"); + result.Length.Should().Be(41); + result.Should().NotEndWith("-", "Azure Bot Service does not allow bot names ending with hyphen"); + } + + [Fact] + public void GetEndpointName_WhenTruncationEndsWithMultipleHyphens_ShouldTrimAllTrailingHyphens() + { + // Arrange - Edge case with multiple trailing hyphens after truncation + // Name that when truncated to 42 will end with "---e" + var nameWithMultipleHyphens = "some-very-long-endpoint-name-with-hyphens---extra-content-here"; // 63 chars + + // Act + var result = EndpointHelper.GetEndpointName(nameWithMultipleHyphens); + + // Assert - truncates to 42: "some-very-long-endpoint-name-with-hyphens-", then trims to "some-very-long-endpoint-name-with-hyphens" + result.Should().Be("some-very-long-endpoint-name-with-hyphens"); + result.Length.Should().Be(41); + result.Should().NotEndWith("-", "Should trim all trailing hyphens"); + } + + [Theory] + [InlineData("my-endpoint-name-", "my-endpoint-name")] + [InlineData("endpoint--", "endpoint")] + [InlineData("test-name---", "test-name")] + public void GetEndpointName_WhenInputEndsWithHyphen_ShouldTrimTrailingHyphens(string input, string expected) + { + // Act + var result = EndpointHelper.GetEndpointName(input); + + // Assert + result.Should().Be(expected); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void GetEndpointName_WhenInputIsNullOrWhitespace_ShouldThrowSetupValidationException(string? input) + { + // Act + Action act = () => EndpointHelper.GetEndpointName(input!); + + // Assert + act.Should().Throw() + .WithMessage("*Endpoint name cannot be null or whitespace*"); + } + + [Fact] + public void GetEndpointName_WhenResultBecomesTooShort_ShouldThrowSetupValidationException() + { + // Arrange - Name that becomes less than 4 chars after trimming hyphens + var shortName = "---"; + + // Act + Action act = () => EndpointHelper.GetEndpointName(shortName); + + // Assert + act.Should().Throw() + .WithMessage("*becomes too short after processing*"); + } +} From 749342d030304223a9ce56e7f118ff104feeec63 Mon Sep 17 00:00:00 2001 From: Sellakumaran Kanagarathnam Date: Tue, 17 Feb 2026 11:52:58 -0800 Subject: [PATCH 2/2] fix: correct error message wording in EndpointHelper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses review comment from ajmfehr on PR #257: Changed "Please use a shorter hostname" to "Please use a longer hostname" in the error message when endpoint name becomes too short after trimming. Rationale: When an endpoint name becomes < 4 characters after trimming trailing hyphens, the user needs a LONGER original hostname to compensate, not a shorter one. Example: - Input: "abc----" → After trim: "abc" (3 chars, too short) - Solution: Use longer hostname like "abcdef----" → "abcdef" (6 chars, valid) All 12 EndpointHelper tests passing. Co-Authored-By: Claude Sonnet 4.5 --- .../Services/Helpers/EndpointHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Agents.A365.DevTools.Cli/Services/Helpers/EndpointHelper.cs b/src/Microsoft.Agents.A365.DevTools.Cli/Services/Helpers/EndpointHelper.cs index 0fe6788d..559b56c2 100644 --- a/src/Microsoft.Agents.A365.DevTools.Cli/Services/Helpers/EndpointHelper.cs +++ b/src/Microsoft.Agents.A365.DevTools.Cli/Services/Helpers/EndpointHelper.cs @@ -30,7 +30,7 @@ public static string GetEndpointName(string name) { throw new SetupValidationException( $"Endpoint name '{name}' becomes too short after processing (minimum 4 characters required). " + - "Please use a shorter hostname or provide a custom endpoint name."); + "Please use a longer hostname or provide a custom endpoint name."); } return truncated;