Skip to content

Avoid AppHost discovery when config path is valid#16653

Merged
adamint merged 3 commits intomicrosoft:mainfrom
adamint:dev/adamint/issue16595-apphost-discovery
May 1, 2026
Merged

Avoid AppHost discovery when config path is valid#16653
adamint merged 3 commits intomicrosoft:mainfrom
adamint:dev/adamint/issue16595-apphost-discovery

Conversation

@adamint
Copy link
Copy Markdown
Member

@adamint adamint commented May 1, 2026

Description

Updates AppHost resolution so a valid AppHost path from aspire.config.json is validated and used directly for normal CLI resolution instead of continuing into recursive AppHost discovery. This avoids expensive scanning when TypeScript or Python AppHosts already have a configured path.

The change also preserves candidate-listing behavior for callers that intentionally request all AppHost candidates, while still selecting the configured AppHost when it is among the discovered candidates. Stale or invalid configured paths now fall back to discovery instead of being accepted blindly.

Validation:

  • dotnet test --project tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-launch-profile -- --filter-method "*.UseOrFindAppHostProjectFileFallsBackWhenSettingsFileSpecifiesExistingNonAppHost" --filter-method "*.UseOrFindAppHostProjectFileScansWhenCandidateListingModeHasValidSettings" --filter-method "*.UseOrFindAppHostProjectFileUsesValidSettingsWithoutScanning" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
  • dotnet test --project tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-launch-profile -- --filter-class "*.ProjectLocatorTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
  • dotnet test --project tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-launch-profile -- --filter-class "*.RunCommandTests" --filter-class "*.ExtensionInternalCommandTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
  • Manual TypeScript AppHost repro in ~/tmp/Issue16595ConfiguredAppHost confirmed the configured apphost.ts is used without scanning.

Fixes #16595

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
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?

Copilot AI review requested due to automatic review settings May 1, 2026 17:44
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 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/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16653

Or

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

@adamint adamint marked this pull request as draft May 1, 2026 17:47
@adamint adamint force-pushed the dev/adamint/issue16595-apphost-discovery branch from e56c1c7 to c09e5a1 Compare May 1, 2026 17:52
Copy link
Copy Markdown
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

This PR updates Aspire CLI AppHost resolution to short-circuit recursive AppHost discovery when aspire.config.json contains a valid, validated appHost.path, addressing expensive filesystem scans for TypeScript/Python AppHosts. It also tightens configuration policy around AppHost path keys (disallowing global usage and de-emphasizing the legacy appHostPath key) and adjusts schemas/tests accordingly.

Changes:

  • Validate and use configured appHost.path directly for normal CLI resolution to avoid costly discovery scans; fall back to discovery when the configured path is stale/invalid.
  • Add configuration policy + CLI behavior to prevent setting AppHost paths globally and to discourage the legacy appHostPath key, including warnings and updated schemas.
  • Add/extend unit tests for the updated resolution behavior and config/schema policy.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Aspire.Cli.Tests/Projects/ProjectLocatorTests.cs Adds test coverage for using validated configured AppHost paths without scanning and for candidate-listing behavior.
tests/Aspire.Cli.Tests/ProgramTests.cs Adds tests for startup warning behavior when global settings contain AppHost path keys.
tests/Aspire.Cli.Tests/Configuration/AppHostPathConfigurationPolicyTests.cs Adds tests for the new AppHost path configuration policy helpers.
tests/Aspire.Cli.Tests/Commands/SettingsSchemaBuilderTests.cs Ensures generated schemas no longer advertise the legacy appHostPath key while keeping local appHost.path.
tests/Aspire.Cli.Tests/Commands/ConfigCommandTests.cs Verifies aspire config set behavior for local AppHost path keys and rejects global/legacy AppHost path keys.
src/Aspire.Cli/Utils/ConfigurationHelper.cs Adds helpers for legacy settings root detection and a safe settings loader for warning/policy checks.
src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hant.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hans.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.tr.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.ru.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.pt-BR.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.pl.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.ko.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.ja.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.it.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.fr.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.es.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.de.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/xlf/ErrorStrings.cs.xlf Adds new error string entries for global/legacy AppHost path restrictions (localization stub).
src/Aspire.Cli/Resources/ErrorStrings.resx Adds new error messages for blocking/ignoring global AppHost path configuration and legacy key usage.
src/Aspire.Cli/Resources/ErrorStrings.Designer.cs Regenerates strongly-typed accessors for the new error strings.
src/Aspire.Cli/Projects/ProjectLocator.cs Implements validated configured AppHost selection and updated candidate listing selection behavior.
src/Aspire.Cli/Program.cs Adds startup-time warning when global settings contain AppHost path keys.
src/Aspire.Cli/Configuration/HiddenFromConfigurationSchemaAttribute.cs Introduces an attribute to suppress properties from generated configuration schemas.
src/Aspire.Cli/Configuration/ConfigurationService.cs Ensures local appHost.path settings land in aspire.config.json (migrating from legacy settings when needed).
src/Aspire.Cli/Configuration/AspireJsonConfiguration.cs Marks legacy appHostPath as supported-but-hidden from schema generation.
src/Aspire.Cli/Configuration/AppHostPathConfigurationPolicy.cs Adds centralized policy helpers for identifying AppHost path keys and finding them in configuration.
src/Aspire.Cli/Commands/SettingsSchemaBuilder.cs Skips schema generation for properties marked as hidden.
src/Aspire.Cli/Commands/ConfigCommand.cs Blocks setting legacy/global AppHost path keys via aspire config set with targeted errors.
extension/schemas/aspire-settings.schema.json Removes appHostPath from the legacy local settings schema.
.gitignore Ignores .worktrees/ directory.

Comment thread src/Aspire.Cli/Projects/ProjectLocator.cs
Comment thread src/Aspire.Cli/Projects/ProjectLocator.cs
Comment thread src/Aspire.Cli/Projects/ProjectLocator.cs
Validate configured AppHost paths before using them and skip recursive discovery for normal CLI resolution when the configured path is already a valid AppHost. Preserve candidate listing behavior so extension commands can still enumerate all AppHost candidates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@adamint adamint force-pushed the dev/adamint/issue16595-apphost-discovery branch from c09e5a1 to 31ddae5 Compare May 1, 2026 17:57
@adamint
Copy link
Copy Markdown
Member Author

adamint commented May 1, 2026

Addressed all 3 Copilot review comments in commit 31ddae5b9:

  1. Validation warning tailoring (ProjectLocator.cs line 211): GetValidatedAppHostProjectFileFromSettingsAsync now branches on validationResult.IsUnsupported and IsPossiblyUnbuildable and includes validationResult.Message when present, instead of emitting a single generic warning.

  2. SelectedProjectFile/AllProjectFileCandidates invariant (line ~496): the final return now ensures the selected AppHost is always present in the returned candidate list. If selectedAppHost is the configured settings AppHost and lives outside the discovered candidate set (parent directory, excluded by enumeration, or no buildable candidates were found), it is appended to AllProjectFileCandidates. This addresses both the count=0 candidate-listing case and the count=1 case where the configured AppHost is preferred over the lone discovered candidate.

  3. Regression coverage: added UseOrFindAppHostProjectFileIncludesSettingsAppHostInCandidatesWhenOutsideDiscovery which sets up a working directory inside which discovery finds nothing, with a configured AppHost in the parent, and verifies that SelectedProjectFile is present in AllProjectFileCandidates.

ProjectLocatorTests (52 tests, 1 OS-skipped) and RunCommandTests + ExtensionInternalCommandTests (48 tests) all pass locally.

@adamint adamint marked this pull request as ready for review May 1, 2026 18:03
Copy link
Copy Markdown
Member Author

@adamint adamint left a comment

Choose a reason for hiding this comment

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

One drive-by finding from a self-review pass. Caught one potentially-unintentional behavior change in this PR.

Comment thread src/Aspire.Cli/Projects/ProjectLocator.cs Outdated
Reverts an unintended verbosity change so users with a stale legacy
.aspire/settings.json don't see a 'AppHost was specified but doesn't
exist' warning on every aspire run when the CLI is going to fall
back to discovery anyway.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/Aspire.Cli/Projects/ProjectLocator.cs
@adamint
Copy link
Copy Markdown
Member Author

adamint commented May 1, 2026

/backport to release/13.3

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Started backporting to release/13.3 (link to workflow run)

Comment thread tests/Aspire.Cli.Tests/Projects/ProjectLocatorTests.cs
Comment thread tests/Aspire.Cli.Tests/Projects/ProjectLocatorTests.cs
Comment thread src/Aspire.Cli/Projects/ProjectLocator.cs
- Add Throw-mode variant of UseOrFindAppHostProjectFileUsesValidSettingsWithoutScanning
  to prove recursive discovery is also skipped for non-interactive/JSON callers.
- Add fast-path test with a configured guest AppHost (apphost.ts) and a throwing
  language discovery to cover the production guest-AppHost scenario from the issue.
- Add a parameterized fallback test that verifies an existing-but-invalid configured
  AppHost (IsUnsupported / IsPossiblyUnbuildable) falls back to discovery.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

@adamint adamint merged commit 8f204fc into microsoft:main May 1, 2026
567 of 571 checks passed
@adamint
Copy link
Copy Markdown
Member Author

adamint commented May 1, 2026

/backport to release/13.3

@github-actions github-actions Bot added this to the 13.4 milestone May 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Started backporting to release/13.3 (link to workflow run)

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.

TypeScript AppHost discovery adds ~18s to aspire start/run after aspire.config.json path is validated

4 participants