Fix Spectre markup rendering in CLI selection prompts#14497
Open
joperezr wants to merge 2 commits intorelease/13.2from
Open
Fix Spectre markup rendering in CLI selection prompts#14497joperezr wants to merge 2 commits intorelease/13.2from
joperezr wants to merge 2 commits intorelease/13.2from
Conversation
The blanket EscapeMarkup() added to the UseConverter in PromptForSelectionAsync/PromptForSelectionsAsync (PR #14422) escaped all markup including the intentional [bold]...[/] used by AddCommand.PackageNameWithFriendlyNameIfAvailable, causing literal '[bold]postgresql[/]' to appear in 'aspire add' output. Fix: remove blanket escaping from the generic converter and instead escape dynamic values at each caller site that formats user-controlled or file-system content (file paths, package names, channel details, publish prompt options), while preserving intentional Spectre markup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14497Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14497" |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a regression introduced by PR #14422 where blanket EscapeMarkup() calls in ConsoleInteractionService.PromptForSelectionAsync and PromptForSelectionsAsync broke intentional Spectre markup rendering in CLI selection prompts, specifically the [bold]...[/] formatting used in the aspire add command.
Changes:
- Removed blanket
.EscapeMarkup()from selection prompt converters inConsoleInteractionService - Added targeted escaping at 9 caller sites that format user-controlled or file-system content (paths, versions, channels, publisher names)
- Preserved intentional
[bold]...[/]markup by escaping only the dynamic data within formatted strings - Added 2 regression tests to verify markup preservation and proper escaping patterns
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/Aspire.Cli/Interaction/ConsoleInteractionService.cs |
Removed blanket .EscapeMarkup() from PromptForSelectionAsync and PromptForSelectionsAsync converters |
src/Aspire.Cli/Commands/AddCommand.cs |
Escaped package names, versions, and channel details while preserving [bold] markup in friendly names |
src/Aspire.Cli/Commands/NewCommand.cs |
Escaped package versions, channel names, and template descriptions |
src/Aspire.Cli/Commands/UpdateCommand.cs |
Escaped channel names and source details |
src/Aspire.Cli/Projects/ProjectLocator.cs |
Escaped file paths in 2 project selection sites |
src/Aspire.Cli/Projects/SolutionLocator.cs |
Escaped solution file paths |
src/Aspire.Cli/Backchannel/AppHostConnectionResolver.cs |
Escaped connection display strings in 2 sites |
src/Aspire.Cli/Commands/InitCommand.cs |
Escaped project file names in 2 selection prompts |
src/Aspire.Cli/Commands/PipelineCommandBase.cs |
Escaped publish prompt option values from AppHost |
src/Aspire.Cli/Commands/PublishCommand.cs |
Escaped publisher names from AppHost |
tests/Aspire.Cli.Tests/Interaction/ConsoleInteractionServiceTests.cs |
Added 2 tests verifying markup preservation and proper escaping patterns |
tests/Aspire.Cli.Tests/Interaction/ConsoleInteractionServiceTests.cs
Outdated
Show resolved
Hide resolved
…sts.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
mitchdenny
approved these changes
Feb 13, 2026
Contributor
🎬 CLI E2E Test RecordingsThe following terminal recordings are available for commit
📹 Recordings uploaded automatically from CI run #22005768884 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The blanket
EscapeMarkup()added to theUseConverterinPromptForSelectionAsync/PromptForSelectionsAsync(PR #14422) escaped all markup — including the intentional[bold]...[/]used byAddCommand.PackageNameWithFriendlyNameIfAvailable. This caused literal[bold]postgresql[/]text to appear in theaspire addselection menu instead of bold-formatted text.Root Cause
Commit 0e2fce7 (PR #14422) was a broad markup-escaping pass to fix crashes when user-controlled strings containing
[brackets](like Azure subscription names, IPv6 addresses, file paths) were passed to Spectre.Console. The fix correctly identified the problem but applied escaping too broadly — at the genericUseConverterlevel inConsoleInteractionService— which broke all callers that intentionally produce Spectre markup.Fix
PromptForSelectionAsync/PromptForSelectionsAsyncconverters inConsoleInteractionServiceAddCommand— package names, versions, channel details (preserving[bold]markup)NewCommand— package versions, channel names, template descriptionsUpdateCommand— version + source detailsProjectLocator— file paths (2 sites)SolutionLocator— file pathsAppHostConnectionResolver— file paths (2 sites)InitCommand— project file names (2 sites)PipelineCommandBase— publish prompt options from AppHostPublishCommand— publisher names from AppHostCallers with hardcoded/resource strings (e.g.,
ConfigCommand,NuGetConfigPrompter,LanguageService,DotNetTemplateFactory) were audited and confirmed safe — no changes needed.Tests
[bold]...[/])