Skip to content

Conversation

@davidfowl
Copy link
Member

Description

Fixes multiple Spectre Console markup escaping bugs across CLI commands that could cause crashes or garbled output when resource names, file paths, version strings, or other external data contain characters that Spectre interprets as markup (e.g., square brackets [], angle brackets <>).

Root cause: Several places in the CLI pass user/external data directly into AnsiConsole.MarkupLine() or SelectionPrompt.UseConverter() without calling .EscapeMarkup() first. When that data contains [brackets], Spectre treats them as formatting directives, causing InvalidOperationException or corrupted output.

Changes:

  • RunCommand: Escape resource names and endpoint URLs in the endpoints grid, and escape log file paths in error messages. Moved .EscapeMarkup() from exception messages (which feed into DisplayError, which already escapes) to log file paths (which feed into DisplayMessage, which does not).
  • LogsCommand: Escape resource names in colorized log output.
  • TelemetryLogsCommand / TelemetrySpansCommand: Escape resource names in telemetry output.
  • ConsoleInteractionService: Escape choice text in PromptForSelectionAsync and PromptForSelectionsAsync converters. Escape version strings and capability names in DisplayIncompatibleVersionError and DisplayVersionUpdateNotification.

Fixes #13955

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
    • No

- ConsoleInteractionService: Escape appHostHostingVersion, RequiredCapability
  in DisplayIncompatibleVersionError, and newerVersion/updateCommand in
  DisplayVersionUpdateNotification
- RunCommand: Remove double-escaping of ex.Message before DisplayError
  (lines 355,362,371), escape resource/endpoint names in Markup (line 313),
  escape log file paths in DisplayMessage (lines 366,375,850)
- LogsCommand: Escape logLine.ResourceName in MarkupLine (line 337)
- TelemetryLogsCommand/TelemetrySpansCommand: Escape resourceName in
  MarkupLine (lines 261,267)
- Add tests: DisplayError double-escape verification, DisplayMessage with
  escaped/unescaped paths, DisplaySubtleMessage default escaping,
  choice prompt with bracket-containing Azure subscription names
Copilot AI review requested due to automatic review settings February 10, 2026 04:17
@github-actions
Copy link
Contributor

github-actions bot commented Feb 10, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14422

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14422"

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes multiple Spectre.Console markup-escaping issues in Aspire CLI output/prompting paths to prevent crashes or corrupted rendering when external data contains markup characters (notably [ / ]), aligning with the root cause described in #13955.

Changes:

  • Escapes external data used in Spectre markup output across run, logs, and telemetry commands.
  • Escapes choice display text in ConsoleInteractionService selection prompts and escapes version/capability strings in version-related messages.
  • Adds tests covering markup escaping behavior for several interaction-service output paths and a publish prompting scenario.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/Aspire.Cli.Tests/Interaction/ConsoleInteractionServiceTests.cs Adds tests validating escaping behavior for version/error/message output paths.
tests/Aspire.Cli.Tests/Commands/PublishCommandPromptingIntegrationTests.cs Adds an integration test scenario involving bracketed choice labels (Azure subscription-like strings).
src/Aspire.Cli/Interaction/ConsoleInteractionService.cs Escapes selection prompt converter output; escapes some version/capability values in markup output.
src/Aspire.Cli/Commands/TelemetrySpansCommand.cs Escapes resource name in span output markup.
src/Aspire.Cli/Commands/TelemetryLogsCommand.cs Escapes resource name in log output markup.
src/Aspire.Cli/Commands/RunCommand.cs Escapes resource/endpoint display in endpoint grid; adjusts escaping responsibilities between DisplayError and DisplayMessage call sites.
src/Aspire.Cli/Commands/LogsCommand.cs Escapes resource name in colorized log prefix.

Copy link
Member

@mitchdenny mitchdenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! The fix correctly moves escaping to the right boundary — caller-side for DisplayMessage (which passes through to MarkupLine), removed from DisplayError callers (which escapes internally). Tests are thorough and document the contract well.

One minor nit: cliInformationalVersion on line 193 of ConsoleInteractionService.cs is not escaped while the adjacent appHostHostingVersion and ex.RequiredCapability are — worth a quick fix for consistency.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 10, 2026

🎬 CLI E2E Test Recordings

The following terminal recordings are available for commit 8a56cbc:

Test Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
CreateAndDeployToDockerCompose ▶️ View Recording
CreateAndDeployToDockerComposeInteractive ▶️ View Recording
CreateAndPublishToKubernetes ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateEmptyAppHostProject ▶️ View Recording
CreateStartAndStopAspireProject ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
ResourcesCommandShowsRunningResources ▶️ View Recording

📹 Recordings uploaded automatically from CI run #21855293083

- RunCommand: escape endpoint URL in link= attribute (IPv6 [::1] URLs crash Spectre)
- ConsoleInteractionService: escape cliInformationalVersion (brackets in build metadata crash Spectre)
- Verified: LogsCommand double-escaping is NOT a bug (both approaches produce identical markup)
@davidfowl davidfowl force-pushed the davidfowl/fix-cli-output branch from 054ba91 to a3130b9 Compare February 10, 2026 06:53
@davidfowl davidfowl merged commit 0e2fce7 into main Feb 10, 2026
669 of 675 checks passed
@davidfowl davidfowl deleted the davidfowl/fix-cli-output branch February 10, 2026 08:19
@dotnet-policy-service dotnet-policy-service bot added this to the 13.2 milestone Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[AspireE2E] Failed to select or search Azure subscription with error " Could not find color or style 'Prod'." when deploying aspire project to Azure

2 participants