Skip to content

Honor --source during template discovery - #19351

Merged
Adam Ratzman (adamint) merged 12 commits into
microsoft:mainfrom
adamint:adamint/fix-19338-template-source
Aug 14, 2026
Merged

Adam Ratzman (adamint) merged 12 commits into
microsoft:mainfrom
adamint:adamint/fix-19338-template-source

Conversation

@adamint

@adamint Adam Ratzman (adamint) commented Aug 13, 2026 •

Copy link
Copy Markdown
Member

Description

aspire new --source currently ignores the explicit source while resolving template versions and can contact NuGet.org from an isolated temporary configuration. This breaks project creation in environments where NuGet.org is blocked and package traffic must use an approved proxy.

This change makes the explicit source exclusive for template discovery and installation, including pinned daily, staging, local, and PR channels. The selected channel identity stays unchanged when a channel is requested; without one, the implicit channel owns the result so stale hives cannot attach an unrelated channel identity.

Relative local sources are resolved against the invocation working directory. Missing local directories now fail before discovery or scaffolding, while HTTP sources and file: URIs keep their existing forms.

User-facing usage

aspire new aspire-empty \
  --name SourceTest \
  --output ./SourceTest \
  --language csharp \
  --source https://packagefeedproxy.microsoft.io/nuget/v3/index.json \
  --non-interactive \
  --suppress-agent-init

With an explicit source, template discovery and installation use only that source. The generated project still maps Aspire* to the explicit source and retains the selected channel's non-Aspire fallback for later restores.

Validation

  • Reproduced NuGet.org contact with the reported 13.5.0+11a1277e... staging CLI.
  • Verified a synthesized staging channel discovers and installs Aspire.ProjectTemplates from one explicit local feed while TCP tripwires for NuGet.org and pkgs.dev.azure.com remain untouched.
  • Verified missing local sources fail before scaffolding, including a plausible --source nuget.org typo.
  • Verified relative paths, file: URIs, and Windows fully qualified paths.
  • Aspire.Cli.Tests: 4,944 passed, 33 platform-specific skipped.
  • Full repository build: 0 warnings, 0 errors.

Fixes #19338

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

Adam Ratzman and others added 9 commits August 13, 2026 08:46
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
@github-actions

Copy link
Copy Markdown
Contributor

🚀 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 -- 19351

Or

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates template discovery and installation to honor aspire new --source, including relative local sources.

Changes:

  • Replaces channel fallback feeds with the explicit source during discovery and installation.
  • Resolves relative sources against the invocation directory.
  • Adds focused unit and command tests.
Show a summary per file
File Description
src/Aspire.Cli/Commands/InitCommand.cs Adapts template installation call.
src/Aspire.Cli/Commands/NewCommand.cs Resolves and forwards source overrides.
src/Aspire.Cli/Packaging/PackageChannel.cs Adds fallback-source replacement.
src/Aspire.Cli/Packaging/PackageSourceOverrideMappings.cs Resolves relative source paths.
src/Aspire.Cli/Templating/DotNetTemplateFactory.cs Forwards source during installation.
src/Aspire.Cli/Templating/TemplateNuGetConfigService.cs Applies sources during discovery and installation.
tests/Aspire.Cli.Tests/Commands/NewCommandTests.cs Tests command-level source handling.
tests/Aspire.Cli.Tests/Packaging/PackageSourceOverrideMappingsTests.cs Tests Unix path resolution.
tests/Aspire.Cli.Tests/Templating/TemplateNuGetConfigServiceTests.cs Tests fallback replacement.

Review details

  • Files reviewed: 9/9 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/Aspire.Cli/Templating/TemplateNuGetConfigService.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Copilot AI review requested due to automatic review settings August 13, 2026 18:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 10/10 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3eac62c7-af80-4c5b-b618-6a77db696f6c
Copilot AI review requested due to automatic review settings August 13, 2026 19:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 14/14 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review of --source handling during template discovery. 6 findings: 1 correctness gap that limits the fix to stable/implicit channels, 2 test-validity/robustness issues in the new E2E, 1 missing input validation, 1 API-hazard/doc-accuracy note, and 1 coverage gap.

No blocking objection to the direction — the implicit/stable path is clearly improved — but finding 1 is worth resolving or documenting before merge, since it means the reported scenario is still broken for daily/staging CLIs.

Comment thread src/Aspire.Cli/Packaging/PackageChannel.cs Outdated
Comment thread src/Aspire.Cli/Packaging/PackageChannel.cs Outdated
Comment thread tests/Aspire.Cli.EndToEnd.Tests/EmptyAppHostTemplateTests.cs Outdated
Comment thread tests/Aspire.Cli.EndToEnd.Tests/EmptyAppHostTemplateTests.cs
Comment thread src/Aspire.Cli/Packaging/PackageSourceOverrideMappings.cs
Make explicit sources exclusive for template discovery and installation, validate local directories, and cover pinned channels and real CLI traffic.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 14, 2026 02:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Files not reviewed (1)
  • src/Aspire.Cli/Resources/NewCommandStrings.Designer.cs: Generated file
  • Files reviewed: 29/30 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@adamint
Adam Ratzman (adamint) merged commit f721513 into microsoft:main Aug 14, 2026
723 of 726 checks passed
@github-actions github-actions Bot added this to the 13.6 milestone Aug 14, 2026
@adamint

Copy link
Copy Markdown
Member Author

/backport to release/13.5

@github-actions

Copy link
Copy Markdown
Contributor

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

@IEvangelist

Copy link
Copy Markdown
Member

PR Testing Report

PR Information

Artifact Version Verification

  • Expected (PR head short SHA): 916fecae
  • Installed CLI version: 13.6.0-pr.19351.g916fecae
  • Status: ✅ Verified — installed version embeds the PR head commit 916fecae.

Changes Analyzed

Files Changed

Source (all under src/Aspire.Cli/):

  • Commands/BaseCommand.cs, Commands/InitCommand.cs, Commands/NewCommand.cs, Commands/TemplateCommand.cs
  • NuGet/NuGetPackagePrefetcher.cs
  • Packaging/PackageChannel.cs — new WithFallbackSourceOverride(source)
  • Packaging/PackageSourceOverrideMappings.cs — new ResolveForWorkingDirectory(source, cwd)
  • Templating/DotNetTemplateFactory.cs, Templating/TemplateNuGetConfigService.cs

Tests:

  • tests/Aspire.Cli.EndToEnd.Tests/EmptyAppHostTemplateTests.cs (new CreateEmptyAppHostWithSourceOverrideDoesNotContactNuGetOrg)
  • tests/Aspire.Cli.Tests/Commands/NewCommandTests.cs
  • tests/Aspire.Cli.Tests/NuGet/NuGetPackagePrefetcherTests.cs
  • tests/Aspire.Cli.Tests/Packaging/PackageSourceOverrideMappingsTests.cs
  • tests/Aspire.Cli.Tests/Templating/TemplateNuGetConfigServiceTests.cs

Change Categories

  • CLI changes detected — template version discovery now honors --source
  • Hosting / Dashboard / Component / Template / VS Code extension / CI infra changes

Mechanism (what the fix does)

  1. --source becomes the selected channel's catch-all (*) fallback for template version discovery and installation (PackageChannel.WithFallbackSourceOverride), instead of the channel's default catch-all (NuGet.org). Channel-specific Aspire* feed mappings are retained.
  2. A relative --source is resolved against the working directory (PackageSourceOverrideMappings.ResolveForWorkingDirectory); absolute paths, http(s) URLs, and explicit file: URIs are preserved.
  3. Background template-package metadata prefetch is disabled for the invocation when --source is set.

Test Environment

  • Isolated temp dir: C:\Users\dapine\AppData\Local\Temp\aspire-pr-test-5c2a7f3af67d44fc8162bb9db4a7293c
  • CLI under test: dogfood\pr-19351\bin\aspire.exe (13.6.0-pr.19351.g916fecae)
  • Update notifications disabled (features.updateNotificationsEnabled=false) so the independent CLI update-check could not confound the "no NuGet.org" assertion.
  • All aspire new runs omit --version (passing --version would skip the version-discovery path this PR changes) and use --non-interactive --suppress-agent-init --localhost-tld false --log-level Debug.
  • Windows host cannot block NuGet.org via /etc/hosts + TCP tripwire (as the PR's Linux E2E does), so the assertion mirrors the PR E2E's secondary check: grep the CLI debug logs for api.nuget.org (expect none).

Test Scenarios Executed

Scenario 1: Absolute --source = PR hive (default pr-19351 channel)

Objective: Happy path — create an AppHost using an explicit absolute --source and confirm discovery runs without NuGet.org.
Coverage Type: Happy path
Status: ✅ Passed

Command: aspire new aspire-empty --source <PR hive> --language csharp (no --version)

Observations:

  • Resolving template version... appeared (the discovery path this PR touches ran).
  • Project created (apphost.cs present), exit 0.
  • No nuget.org reference in the run log.

Scenario 2: Relative --source local single-package feed (staging-emulated)

Objective: Core fix — faithful reproduction of the PR's E2E test: emulate a staging identity (whose catch-all would be NuGet.org), provide only the templates package in a relative source-feed, and assert no NuGet.org contact.
Coverage Type: Happy path (core regression)
Status: ✅ Passed

Setup: ASPIRE_CLI_CHANNEL=staging, ASPIRE_CLI_VERSION=13.6.0-pr.19351.g916fecae; source-feed/ contains only Aspire.ProjectTemplates.13.6.0-pr.19351.g916fecae.nupkg.
Command (from within the scenario dir): aspire new aspire-empty --source source-feed --language csharp (no --version)

Evidence (log):

Using source from config: ...\scenario-2\source-feed
Searching 1 source(s) for 'Aspire.ProjectTemplates'

Observations:

  • The relative source-feed was resolved against the working directory (PR's ResolveForWorkingDirectory).
  • Template discovery searched only source-feed — no NuGet.org.
  • Project created (apphost.cs present), exit 0.
  • Note: on this emulated version the named staging channel could not synthesize a feed (no commit hash), so discovery ran on the default channel — whose NuGet.org catch-all was replaced by --source. The successful-synthesis case is covered by Scenario 2b below.

Scenario 2b: Successful staging synthesis — NuGet.org catch-all replaced

Objective: Definitively demonstrate the catch-all replacement on a fully synthesized channel of shape [Aspire* → dnceng, * → NuGet.org].
Coverage Type: Happy path (definitive fix proof)
Status: ✅ Passed

Setup: Same as Scenario 2, plus overrideStagingFeed=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v3/index.json (a real, reachable Aspire staging feed) so the staging channel synthesizes successfully.

Evidence (log):

Resolved 'staging' channel: feed=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v3/index.json, quality=Both
Using source from config: https://pkgs.dev.azure.com/dnceng/.../dotnet9/nuget/v3/index.json
Using source from config: ...\scenario-2b\source-feed
Searching 2 source(s) for 'Aspire.ProjectTemplates'

Observations:

  • The synthesized channel's normal catch-all is * → NuGet.org. With --source, the two sources actually searched were the retained Aspire* → dnceng feed and the source-feed override — NuGet.org was replaced/removed.
  • This exactly matches the PR unit test ResolveTemplatePackageAsync_RequestedChannelWithSourceOverride_ReplacesFallbackSource (sources == [channelSource, sourceOverride]).
  • Project created (apphost.cs present), exit 0. No nuget.org anywhere in the log.

Scenario 3: Invalid --source (nonexistent feed) — unhappy path

Objective: Ensure a bad --source does not silently fall back to NuGet.org, and fails cleanly.
Coverage Type: Unhappy path / negative
Status: ✅ Passed (behaves as designed)

Setup: Staging-emulated, overrideStagingFeed removed (so the channel catch-all reverts to NuGet.org). --source no-such-feed points at a nonexistent relative directory.

Evidence (log):

Using source from config: ...\scenario-3\no-such-feed
Searching 1 source(s) for 'Aspire.ProjectTemplates'
Warning: Failed to search ...\scenario-3\no-such-feed: The path '...' for the selected source could not be resolved.
❌ No template versions found in channel 'default'.

Observations / Expected Unhappy-Path Outcome:

  • The invalid relative --source was resolved to an absolute path, then used as the sole search source.
  • No fallback to NuGet.org — the invalid source replaced the default channel's NuGet.org catch-all, so discovery did not leak to NuGet.org (this is the inverse of the pre-fix bug aspire new --source still contacts NuGet.org during template discovery #19338).
  • Clean failure: clear ❌ No template versions found in channel 'default'. message, exit code 1, no project created.

Summary

Scenario Coverage Status Key evidence
1 — Absolute --source = PR hive Happy ✅ Passed discovery ran; apphost.cs; no nuget.org
2 — Relative source-feed (staging emu) Happy (core) ✅ Passed searched only source-feed; relative resolved; no nuget.org
2b — Successful staging synth Happy (definitive) ✅ Passed searched [dnceng, source-feed]; NuGet.org catch-all replaced; no nuget.org
3 — Invalid --source Unhappy ✅ Passed only bad source searched; no nuget.org fallback; clean fail (exit 1)

Cross-cutting check: grep of all scenario logs for api.nuget.org → zero matches (matches the PR E2E's assertion ! grep -R -F 'api.nuget.org' logs).

Overall Result

✅ PR VERIFIED

--source is now honored throughout template version discovery and installation: it replaces the selected channel's NuGet.org catch-all (Scenario 2b), works with relative feed paths (Scenarios 2 & 3), and — critically for the reported bug — prevents any fallback to NuGet.org, whether the source is valid (Scenarios 1/2/2b) or invalid (Scenario 3). Behavior matches the PR's own E2E and unit tests.

Notes / Caveats

  • Testing was performed on Windows using debug-log inspection for the "no NuGet.org" assertion (the network tripwire in the PR's Linux E2E is not reproducible on the host). Sources actually queried are logged verbatim by aspire-managed nuget search, so the assertion is direct rather than inferred.
  • aspire-empty uses an embedded template body, so these scenarios validate the version-discovery / source-selection path (the code this PR changes). The end-to-end package install path via --source is covered by the PR's own unit/E2E tests.

@github-actions github-actions Bot locked and limited conversation to collaborators Sep 14, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

aspire new --source still contacts NuGet.org during template discovery

4 participants