Accept dev localhost resource service URLs#17639
Conversation
Allow DashboardServiceHost to treat RFC-reserved .localhost subdomains as local resource service endpoints so polyglot AppHosts scaffolded with *.dev.localhost can run. Add unit coverage for local endpoint recognition and a CLI E2E regression test that scaffolds and runs an Express/React polyglot AppHost with dev-localhost URLs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17639Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17639" |
PR Testing ReportPR Information
CLI Version Verification
Changes AnalyzedFiles Changed
Change Categories
Test Scenarios ExecutedScenario 1: Express/React polyglot AppHost with *.dev.localhostObjective: Verify a real TypeScript polyglot AppHost scaffolded with Steps:
Evidence:
Observations:
Scenario 2: Non-local resource service URL remains rejectedObjective: Verify the validation is not relaxed to arbitrary DNS names. Steps:
Evidence:
Expected Unhappy-Path Outcome: A clear validation failure and no successful AppHost running state. Summary
Overall Result✅ PR VERIFIED Recommendations
|
There was a problem hiding this comment.
Pull request overview
This PR fixes aspire run failing for polyglot AppHosts that scaffold *.dev.localhost resource service URLs by relaxing the AppHost-side “resource service endpoint must be local” validation to treat RFC 6761 localhost subdomains (and localhost.) as local endpoints, while still rejecting non-local DNS hostnames. This aligns validation with the fact that Kestrel still binds the resource service using ListenLocalhost, so the change relaxes configuration checks without broadening the listener scope.
Changes:
- Updated
DashboardServiceHostendpoint validation to accept.localhostsubdomains (and trailing-dot FQDN forms) as local resource service endpoints. - Added unit test coverage for the local-endpoint classification logic (including
.localhostsubdomains and common lookalikes). - Added an end-to-end CLI smoke test ensuring a polyglot template using
*.dev.localhostcan be created and run successfully.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/Aspire.Hosting/Dashboard/DashboardServiceHost.cs | Replaces Uri.IsLoopback-only check with IsLocalResourceServiceEndpoint that also accepts .localhost subdomains and localhost.. |
| tests/Aspire.Hosting.Tests/Dashboard/DashboardServiceHostTests.cs | Adds coverage for .localhost subdomain acceptance and non-local hostname rejection. |
| tests/Aspire.Cli.EndToEnd.Tests/SmokeTests.cs | Adds E2E regression test for aspire new + aspire run with useDevLocalhost polyglot template setting. |
|
/backport to release/13.4 |
|
Started backporting to |
|
❓ CLI E2E Tests unknown — 108 passed, 0 failed, 2 unknown (commit View all recordings
📹 Recordings uploaded automatically from CI run #26611998521 |
| var host = uri.Host.EndsWith(".", StringComparison.Ordinal) | ||
| ? uri.Host[..^1] | ||
| : uri.Host; | ||
|
|
||
| // RFC 6761 reserves "localhost." and names under it for loopback resolution: | ||
| // https://www.rfc-editor.org/rfc/rfc6761#section-6.3. Uri.IsLoopback only | ||
| // recognizes "localhost" itself, but Aspire-generated polyglot AppHosts can use | ||
| // scoped names like "myapp.dev.localhost". | ||
| return string.Equals(host, KnownHostNames.Localhost, StringComparison.OrdinalIgnoreCase) | ||
| || host.EndsWith(".localhost", StringComparison.OrdinalIgnoreCase); |
There was a problem hiding this comment.
There are existing helper methods for testing whether a host is localhost or dev.localhost, etc on EndpointHostHelpers
| const string projectName = "PolyglotDevLocalhost"; | ||
| await auto.AspireNewAsync(projectName, counter, template: AspireTemplate.ExpressReact, useDevLocalhost: true); | ||
|
|
||
| await auto.RunCommandFailFastAsync($"cd {projectName}", counter); |
There was a problem hiding this comment.
Need to rebase. This has been replaced with RunCommandAsync
JamesNK
left a comment
There was a problem hiding this comment.
LGTM. The validation logic correctly handles RFC 6761 .localhost subdomains and trailing-dot edge cases, and Kestrel still binds only to loopback — no new network surface exposed. Tests have good positive/negative coverage.
|
@copilot follow up on fixes for the PR comments |
Co-authored-by: danegsta <50252651+danegsta@users.noreply.github.com>
Fixed in 5fa2946. |
|
/backport to release/13.4 |
|
Started backporting to |
Documents the fix from microsoft/aspire#17639 where aspire run now correctly accepts *.localhost subdomains (per RFC 6761) as local resource service endpoints, enabling polyglot AppHosts scaffolded with *.dev.localhost URLs to run without error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Pull request created: #1120
|
|
📝 Documentation has been drafted in microsoft/aspire.dev#1120 targeting Updated Note This draft PR needs human review before merging. |
Description
aspire runfails for polyglot AppHosts scaffolded with*.dev.localhostURLs because the AppHost resource service endpoint validation only acceptedUri.IsLoopback, which does not recognize RFC-reserved localhost subdomains.This updates the resource service endpoint check to treat
localhost, loopback IPs, and.localhostsubdomains as local while still rejecting arbitrary DNS names and lookalikes. Kestrel continues to bind the resource service withListenLocalhost, so this relaxes configuration validation without exposing a new network listener.User-facing usage
Users can scaffold and run a polyglot AppHost with
*.dev.localhostURLs:Security considerations
This change relies on RFC 6761's reservation of
localhostand names below it for loopback use. The resource service still binds withListenLocalhost, and non-.localhosthostnames remain rejected.Validation:
dotnet build tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csprojdotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-class "*.DashboardServiceHostTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"./localhive.sh -o /tmp/aspire-e2e-devlocalhost -r linux-arm64 --archiveASPIRE_E2E_ARCHIVE=/tmp/aspire-e2e-devlocalhost.tar.gz dotnet test --project tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csproj --no-launch-profile -- --filter-method "*.CreateAndRunPolyglotAppHostWithDevLocalhostUrls" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"Fixes # (issue)
Checklist
<remarks />and<code />elements on your triple slash comments?