Forward-port release/13.4 fixes to main - #17775
Forward-port release/13.4 fixes to main#17775David Fowler (davidfowl) wants to merge 15 commits into
Conversation
…rce mapping (#17528) * Bake AspireCliChannel=staging for release-branch builds even when stabilizing The channel-compute step in build_sign_native.yml was checking $versionKind -eq 'release' BEFORE the release-branch regex check. A 13.4 staging build runs from a release/* branch with StabilizePackageVersion=true, which sets DotNetFinalVersionKind=release, so the wrong arm fired and baked AspireCliChannel=stable into the binary. Downstream, aspire init reads CliExecutionContext.IdentityChannel to pick the channel mappings it writes into the workspace nuget.config. With identity=stable there's no Aspire.* → staging-feed mapping, so aspire add tries to resolve packages from nuget.org and either gets 13.3.5 or fails outright (the apphost.cs template pins #:sdk Aspire.AppHost.Sdk@13.4.0+<sha>, which isn't on nuget.org). Swap the conditions so the release-branch check runs first. Release- branch builds are always staging artifacts; only release-shaped non-release-branch builds (effectively none in practice) get stable. Fixes #17527 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add aspireCliChannelOverride pipeline parameter for GA ship builds With release-branch builds now defaulting to 'staging' (so stabilizing dogfood builds aren't mis-baked as 'stable'), there was no remaining path to produce a real 'stable' GA ship binary — the same release/* branch that produces the staging dogfood drops also produces the final ship build, and the pipeline has no other signal to tell them apart. Add a runtime pipeline parameter 'aspireCliChannelOverride' (auto | stable | staging | daily, default auto) to azure-pipelines.yml and thread it through every build_sign_native.yml invocation. When the release manager kicks off the official GA ship build, they set this to 'stable' so the distributed binary bakes AspireCliChannel=stable and aspire init writes the nuget.org-only nuget.config that matches the promoted package set. Routine stabilizing builds leave it on 'auto' and continue to bake 'staging'. The override is validated against the same accepted-channel set that IdentityChannelReader.IsValidChannel enforces at CLI startup so a typo fails the pipeline step rather than producing a binary that refuses to boot. pr-<N> is intentionally excluded from the override set since PR builds always come from the PullRequest reason arm. The unofficial pipeline doesn't get the parameter — its test builds should always derive the channel from branch+reason, and the template's default 'auto' achieves that. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Route stabilizing staging CLI to SHA-derived darc feed The staging-channel synthesis in PackagingService defaulted to PackageChannelQuality.Both for staging-identity CLIs. With Both, useSharedFeed=true and Aspire.* gets routed to the shared dnceng/dotnet9 daily feed -- which only contains prerelease-tagged 13.4.0-preview.* packages, not the stable-shaped 13.4.0 packages produced during release stabilization (StabilizePackageVersion=true). Net effect on the just-shipped staging build of 13.4: `aspire init` drops a NuGet.config pointing Aspire.* at dotnet9, then `aspire add yarp` fails to resolve Aspire.Hosting.Yarp 13.4.0 because dotnet9 doesn't carry it. The packages actually live in the SHA-derived darc-pub-microsoft-aspire-<hash> feed. Fix: when the CLI's identity is staging, derive the synthesized channel's default quality from the CLI build's version shape: - Stable-shaped (no semver prerelease tag) -> Stable, which makes useSharedFeed=false and routes Aspire.* to the SHA-derived darc feed where stabilizing packages actually live. - Prerelease-shaped -> Both (the historical default), since SHA- specific darc feeds are only created for stable release-branch builds and prerelease staging CLIs must use the shared feed. The identity-staging branch runs before the requested/configured branches in the if/else because `init` (and many other commands) calls GetChannelsAsync(requestedChannelName: "staging") when the running CLI's identity is staging -- short-circuiting on the requested branch would re-introduce the bug. The version-shape predicate is injected via constructor so unit tests can deterministically exercise both paths regardless of the test-host assembly's baked InformationalVersion. Validated end-to-end with a locally-built NAOT `aspire` binary (`/p:AspireCliChannel=staging`) + overrideStagingFeed pointing at darc-pub-microsoft-aspire-0f514452: `aspire init` -> `aspire add yarp` now resolves Aspire.Hosting.Yarp 13.4.0 instead of falling back to 13.3.5. Refs #17527 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Pin PackagingService stable-shape predicate to false in CliTestHelper The stabilization-check CI job builds the test host with StabilizePackageVersion=true, which bakes a stable-shaped (no '-') informational version into Aspire.Cli. PackagingService's new identity-staging branch then defaults quality to Stable and requires a SHA suffix in the assembly's InformationalVersion to compute the darc-pub feed URL. Stabilized test-host assemblies don't carry a +sha suffix, so CreateStagingChannel returned null and the UpdateCommand_WhenStagingIdentityRegistersChannel_UsesStagingForUnpinnedProject test fell back to the default channel instead of staging. Default CliTestHelper.PackagingServiceFactory to inject isStableShapedCliVersion: () => false so command-level tests get deterministic prerelease-shaped behavior (quality=Both → shared dotnet9 feed) regardless of how the test host was built. Tests that specifically exercise the stable-shape branch (in PackagingServiceTests) construct PackagingService directly and already pass an explicit predicate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update eng/pipelines/templates/build_sign_native.yml --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jose Perez Rodriguez <joperezr@microsoft.com> (cherry picked from commit 6a82355) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Prefer current CLI template version Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Pin aspire new template version to CLI Ensure CLI-runtime templates selected from explicit package channels use the current bundled CLI/SDK version instead of floating to newer channel packages that can mismatch the bundled AppHost server. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit 3f0998a) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Folder path (#17573) * Stabilize PrebuiltAppHostServer staging globalPackagesFolder path PackagingService creates the staging channel with ConfigureGlobalPackagesFolder=true so each darc/override feed restore lands in an isolated cache (two staging builds of the same release branch ship as 13.4.0 but from different feeds, and NuGet keys by (id,version) only). PrebuiltAppHostServer was wiring that flag into a TemporaryNuGetConfig whose default globalPackagesFolder value is the relative '.nugetpackages' -- NuGet resolved it under the temp config's own directory, BundleNuGetService baked those temp paths into integration-package-probe-manifest.json, and TemporaryNuGetConfig.Dispose then recursively deleted the cache out from under the manifest. On macOS osx-arm64 polyglot staging builds this surfaced as a hang during DI / assembly loading in aspire-managed. Preserve the per-feed cache isolation behavior and anchor the override at a stable absolute path instead: <ASPIRE_HOME>/.nugetpackages/<first-8-of-CLI-commit-sha> Keying by the truncated commit hash matches the existing darc-pub-microsoft-aspire-<hash> feed URL convention in PackagingService.GetStagingFeedUrl, so the cache key and feed key stay aligned at 8 hex chars. 8 chars is short enough to avoid Windows MAX_PATH blow-ups on deep integration cache trees while keeping SHA collisions negligible. The cache lives under ASPIRE_HOME (not the per-AppHost working directory) so multiple AppHosts on the same machine running against the same staging build can share a single restore -- the unit of isolation here is the staging build, not the individual restore command. Mechanics: - TemporaryNuGetConfig.CreateAsync now accepts an optional globalPackagesFolderValue and propagates it through AddGlobalPackagesFolderToConfigAsync into the merger. - NuGetConfigMerger.AddGlobalPackagesFolderConfiguration takes the optional override and falls back to the workspace-relative default ('.nugetpackages') for the non-temp workspace-merge path. - PrebuiltAppHostServer.ResolveStableGlobalPackagesFolder routes both temp config branches (channel and package-source-override) through the new helper. - VersionHelper.TryGetCurrentCommitHashShort surfaces the truncated SHA from the running CLI's AssemblyInformationalVersion (returns null on clean release builds with no '+sha' suffix; callers fall back to 'default'). - CliPathHelper centralizes the '<ASPIRE_HOME>/.nugetpackages' path so the producer (PrebuiltAppHostServer) and consumer (CacheCommand) can't drift. - CacheCommand.ClearCommand now wipes <ASPIRE_HOME>/.nugetpackages so a wedged staging restore is recoverable through the same UX as every other CLI cache. Tests: - Updated existing PrebuiltAppHostServerTests staging cases to assert the globalPackagesFolder value is absolute and lives outside the temp config directory. - New PrebuiltAppHostServerTests case wires a real PackagingService with overrideStagingFeed on a stable-shaped CLI and pins the same invariant end-to-end. - New TemporaryNuGetConfigTests for the override propagation and for the no-override-when-disabled invariant. - New CacheCommandTests covering the staging cache wipe and the missing-cache no-op path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Key staging globalPackagesFolder cache by feed URL hash The staging globalPackagesFolder fix in the previous commit keyed the \`.nugetpackages\` subdirectory off the CLI's own commit SHA (first 8 hex chars of \`AssemblyInformationalVersionAttribute\`). That handles two darc-shipped staging builds of the same release branch, but it breaks the local-dev case where one CLI is repeatedly retargeted at different \`overrideStagingFeed\` values: the URL changes but the SHA doesn't, so every override silently shares one cache bucket and the second restore reuses the first feed's now-stale \`13.4.0\` assemblies. Switch the cache key to the first 8 hex chars of \`XxHash3\` over the trimmed, lower-cased resolved feed URL: - Override branch passes the explicit \`--source\` URL. - Channel branch passes the channel's \`Aspire*\` mapping source (or the first mapping for forward compatibility). Trim + lower-case before hashing so a stray whitespace from a config file or a hostname-case change doesn't fragment the cache. Non-cryptographic hashing is fine here — the key is a directory name, not a security boundary — and 8 hex chars keep deep integration cache paths well under Windows MAX_PATH while giving ~4 billion buckets, so collisions are negligible across the handful of staging feeds any user ever sees. Removes the now-unused \`VersionHelper.TryGetCurrentCommitHashShort\` helper (added in the previous commit, no remaining callers). Tests: - New \`CliPathHelperTests.ComputeStagingFeedCacheKey_*\` cover determinism, normalization, length defaults, and null/empty input. - Existing \`PrebuiltAppHostServerTests\` strengthened to assert the emitted globalPackagesFolder equals \`<aspireHome>/.nugetpackages/<hash(feed)>\`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Narrow #17564 CLI-pin fallback to prerelease channels PR #17564 introduced a new fallback in TryGetCurrentCliTemplateVersionPackage that pins the template package to the running CLI's SDK version whenever the selected channel is explicit and not local-build. That preserved the intended fix for prerelease channels (daily, staging) where the channel feed filters the running CLI's package out of search results even though the feed can still restore it. But it also fired for the stable channel, where the filter does not apply. For a non-stable-shape CLI (PR build like '13.4.0-pr.X.gY' or a daily-shape preview) invoked with '--channel stable', it forced an unpublishable version into the generated apphost.cs, breaking the SmokeTests LatestCliCanStartStableChannelAppHost and LatestCliCanStartStableChannelTypeScriptAppHost. Exclude the stable channel from the new fallback so that case falls through to the OrderByDescending picker and the user gets the highest shipped stable package they explicitly asked for. The original prerelease-channel motivation ('Aspire.TypeSystem version mismatch when 13.4 CLI floats templates to a 13.5 daily preview') is preserved unchanged. Test updates: - NewCommandChannelResolutionTests.NewCommand_NoChannelArg_ResolvesTemplateFromIdentityChannel gets an expectedVersion theory parameter so the daily case still pins to the CLI version while the stable case asserts the highest shipped stable. - NewCommandChannelResolutionTests.NewCommand_ExplicitChannelArg_OverridesIdentityChannel asserts highest shipped stable (matching the SmokeTest contract). - New NewCommand_ExplicitStableChannel_NonStableCliVersion_FallsBackToHighestShippedStable regression test covers both daily-shape and PR-shape CLI identities. - NewCommandTests.NewCommandWithTypeScriptEmptyTemplatePassesResolvedVersionAndChannelToScaffolding reverts to its pre-#17564 assertion of '9.2.0' from the stable feed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit 5d0da8b) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Revert the Corepack-specific Yarn invocation added to the extension build so internal Azure Pipelines builds use the configured Yarn executable instead of downloading Yarn from the public registry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit a0823e6) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…templates (#17637) * Add failing tests for aspire-starter channel resolution on release/13.4 Reproduces the bug where 'aspire new aspire-starter' (and aspire-starter-csharp-typescript) silently resolve Aspire.ProjectTemplates from the Implicit (nuget.org) channel on a daily / staging / release-branch CLI, ignoring CliExecutionContext.IdentityChannel. Passing --channel works because that value is the only thing forwarded into TemplateInputs.Channel today. The new tests pin the contract for both DotNet- and CLI-runtime templates: NewCommand must forward IdentityChannel into inputs.Channel whenever --channel is not passed, so DotNetTemplateFactory.ApplyTemplateAsync uses the identity-matching channel when calling TemplateNuGetConfigService.ResolveTemplatePackageAsync. Coverage across the four shipping identities (pr-<N>, daily, staging, stable) plus three edge cases (unregistered identity falls back to null, explicit --channel overrides identity, --version still forwards identity into inputs.Channel). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Forward IdentityChannel to TemplateInputs.Channel for dotnet-runtime templates When 'aspire new' invoked a TemplateRuntime.DotNet template (e.g. aspire-starter, aspire-starter-csharp-typescript) without an explicit --channel argument, inputs.Channel was left null. That caused TemplateNuGetConfigService.ResolveTemplatePackageAsync to fall back to the Implicit (nuget.org) channel, ignoring the CLI's IdentityChannel. Daily / staging / pr builds would therefore resolve Aspire.ProjectTemplates from nuget.org instead of the channel matching the running CLI. This change mirrors the existing CLI-runtime contract: when --channel is absent and no version-resolution channel was selected, look up the identity channel in the packaging service and forward it to inputs.Channel only when it matches a registered Explicit channel (Implicit matches still resolve to null so the project inherits ambient NuGet configuration). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Consolidate channel precedence into a single resolvedChannelName Address review feedback: collapse the explicitChannelArg / resolvedChannelName / identityChannelName three-way coalesce on TemplateInputs.Channel into a single resolvedChannelName variable with a clear precedence chain (explicit --channel > resolver result > identity). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Explain why identity-channel fallback lives at the call site Document why ResolveIdentityChannelNameAsync is invoked at the TemplateInputs assembly site rather than folded into ResolveCliTemplateVersionAsync: the two paths that need the identity hint (TemplateRuntime.DotNet templates and --version short-circuit) are precisely the ones the resolver never runs on. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit 26b661b) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…7646) The signed-build verifier ran 'aspire new aspire-starter' after extracting the CLI archive, claiming to exercise 'template engine + bundle self-extraction without requiring a NuGet restore'. That claim was wrong: 'aspire new' resolves template versions via TemplateNuGetConfigService.ResolveTemplatePackageAsync, which always queries a NuGet feed. The step only ever succeeded on release branches because builds were mis-baked with AspireCliChannel=stable, which routed the implicit identity-channel lookup to nuget.org and found a previously-shipped Aspire.ProjectTemplates version. Once #17528 corrected the release-branch builds to bake AspireCliChannel=staging, the identity channel switched to a staging feed that is not reachable from the 1ES signed-build agent, and the step started failing with 'No template versions were found' in the internal build pipeline. This is the same egress reason the TypeScript starter check was already removed for (#17274, tracked in #17345). Re-adding meaningful starter coverage in the signed-build verifier requires either an internal NuGet mirror or a no-network template path. Drop the step (and the corresponding test assertion); the verifier still covers archive layout, sidecar contract, and 'aspire --version' execution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit d8c4e96) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Treat Win32Exception while inspecting process metadata as a stale or non-targetable process so stop monitoring does not fail when an AppHost exits during shutdown. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit e258349) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* [release/13.4] Mark Aspire.Hosting.Blazor as preview The 13.4.0 stable build ships gateway scripts only under buildTransitive/net8.0/Scripts/, while the TypeScript AppHost loader resolves Gateway.cs from lib/net8.0/Scripts/. This breaks the TS polyglot AppHost flow out of the box. Mark the package as preview-shaped via SuppressFinalPackageVersion so consumers don't pick it up as stable until the packaging/loader issue is fully addressed. Fixes #17685 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update src/Aspire.Hosting.Blazor/Aspire.Hosting.Blazor.csproj --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit dfd226a) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…fuzzy auto-pick (#17724, #17725) (#17728) * fix(cli): restore implicit-channel discovery + guard non-interactive fuzzy auto-pick (#17724, #17725) ## #17725 — Prerelease-only integrations invisible on polyglot apphosts `IntegrationPackageSearchService.GetIntegrationPackagesWithChannelsAsync` used to narrow the channel set to whatever `configuredChannel` resolved to (from `aspire.config.json`'s `"channel"` field). For a polyglot apphost pinned to a `Quality.Stable` channel this dropped the implicit channel from discovery, so prerelease-only packages (e.g. `Aspire.Hosting.Foundry`, `Aspire.Hosting.Kubernetes`) became invisible. This narrowing was born 2026-01-13 in PR #13705 with a C#-only short-circuit in `GetConfiguredChannel`. It stayed dormant until PR #17452 (2026-05-26) started writing `"channel": "<identity>"` into the scaffolded `aspire.config.json` during `aspire init`. After #17452 every newly-init'd polyglot apphost in 13.4 had the field populated and tripped the narrowing. 13.3.5 users had no `"channel"` persisted, so the bug was invisible there — this is a 13.4 regression introduced by the activator, not the narrowing code itself. The fix removes the narrowing. The configured channel is still forwarded to `PackagingService.GetChannelsAsync` as `requestedChannelName` so out-of-tree apphost staging-channel synthesis keeps working — it just no longer constrains the post-retrieval filter pipeline. The filter pipeline is now byte-identical for C# and polyglot apphosts. ## #17724 — `aspire add <fuzzy> --non-interactive` silently picks first match `AddCommand` falls back to fuzzy search when there's no exact match. The fuzzy candidates were passed to `GetPackageByInteractiveFlow`, which in non-interactive mode auto-selected `distinctPackages.First()` and silently installed it. Combined with #17725, `aspire add kube --non-interactive` on a TS apphost silently installed `Aspire.Hosting.Azure`. The existing guard at AddCommand.cs:181 already refused this when `--version` was supplied. This change generalizes the guard: any non-interactive invocation without an exact match now fails with a new `NonInteractiveRequiresExactPackageMatch` resource message. Fuzzy fallback remains available in interactive mode. ## Tests - IntegrationSearchCommandFormatJsonWithTypeScriptAppHostPinnedToChannelAlsoSearchesImplicitChannel - IntegrationSearchCommandFormatJsonWithTypeScriptAppHostPinnedToStagingChannelAlsoSearchesImplicitChannel - IntegrationSearchCommandFormatJsonWithTypeScriptAppHostPinnedToStableChannelStillSurfacesPrereleaseOnlyPackages (primary regression test for #17725 — Foundry case) - IntegrationSearchCommandTypeScriptAppHostProducesSameResultRegardlessOfPersistedChannel (durable structural guard: parameterized over with/without `"channel"` in aspire.config.json; asserts the result is identical, proving the narrowing is gone) - AddCommand_NonInteractive_NoExactMatchWithoutVersion_FailsInsteadOfFuzzyAutoPick_Regression17724 (primary regression test for #17724) - AddCommand_NonInteractive_ExactMatchWithoutVersion_StillSucceeds (companion guard: exact-match happy path keeps working non-interactive) Two pre-existing AddCommandFuzzySearchTests were testing the buggy auto-pick behavior implicitly (they used `add postgre` / typo input under the default non-interactive test host). Updated to opt into an interactive host environment to assert the documented interactive-fuzzy-prompt behavior. Full Aspire.Cli.Tests suite: 3900 passed, 21 skipped, 0 failed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(cli): restore explicit-channel inclusion when polyglot apphost pins a channel Address review feedback on PR #17728. The first revision dropped too much. Removing the `|| !string.IsNullOrEmpty(configuredChannel)` half of the gate caused a NEW regression: a TS apphost pinned to "daily" / "staging" / a custom channel now searched only the implicit channel, losing access to packages that live on the pinned feed. Production change in IntegrationPackageSearchService: channels = hasHives || !string.IsNullOrEmpty(configuredChannel) ? allChannels : allChannels.Where(c => c.Type is PackageChannelType.Implicit); This preserves the #17725 fix (narrowing is still gone, so the implicit channel always participates and prerelease-only packages like Foundry remain discoverable when pinned to a Stable-quality channel) while keeping pinned explicit channels in the search. Tests strengthened with per-channel invocation counters so that "channel X was searched" is asserted directly rather than inferred from the dedupe outcome. The Theory test is reframed: both arms agree on the user-visible preferred result (Redis 1.0.0, implicit wins), but the with-channel arm additionally hits the daily channel and the without-channel arm does not. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(cli): pin staging-shipping behavior for #17724 + #17725 Adds proof-by-test that the IPSS gate behaves identically when the CLI is shipped as staging (`IdentityChannel == "staging"`) as it does today with the PR dogfood build (where the channel name was `pr-17728`): 1. Adds `[InlineData("\"staging\"", true)]` to the existing theory `…PersistedChannelExpandsDiscoveryWithoutChangingPreferredResult`. This proves the IPSS gate (`hasHives || !string.IsNullOrEmpty( configuredChannel)`) is channel-name-opaque — `"staging"` and `"daily"` produce identical gate behavior. 2. Adds a new fact `IntegrationSearchCommandStagingStampedCliWithPinnedStagingApphost QueriesBothImplicitAndStagingChannelsAndSurfacesPrereleaseOnlyPackages` that exercises the exact shipping shape: * Real PackagingService (not the fake TestPackagingService) — so the real staging-channel synthesis path is exercised. * `IdentityChannel = Staging` — the CLI binary is stamped as the staging release identity, which is how shipped staging CLIs run. * `aspire.config.json` pins `"channel": "staging"` — which is what `aspire new` writes into polyglot apphosts on a staging-stamped CLI (see CliTemplateFactory.TypeScriptStarterTemplate). * No PR hives — this is a real installed CLI, not a dogfood build. Asserts both invariants: (i) Total cache call count >= 2, proving both implicit AND staging channels were queried. Pre-fix narrowing would have produced exactly 1 call. (ii) A prerelease-only package returned only when prerelease=true surfaces to the user — proving the #17725 fix holds on a real staging release, not just on a PR build. Together with the existing `…UsesConfiguredStagingChannelWithRealPackagingService` (apphost-pin triggers staging synthesis under Stable identity) and `…UnpinnedAppHostUsesImplicitChannelUnderStagingCli` (staging identity without pin correctly falls back to implicit-only), the staging quadrant is now fully covered. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix interactive fuzzy add confirmation Prompt before adding a single fuzzy or no-match fallback candidate in interactive aspire add flows, while preserving exact-match auto-selection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: David Fowler <davidfowl@gmail.com> (cherry picked from commit 56e8866) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* API review fixes for 13.4 (PR #17700) Addresses several issues found during API surface review: 1. Rename NetworkID -> NetworkId (and networkID -> networkId) on AllocatedEndpoint, EndpointAnnotation, EndpointReference, EndpointReferenceAnnotation, NetworkEndpointSnapshot, NetworkEndpointSnapshotList, and related methods/parameters. 2. Add [Experimental("ASPIREAZURE003")] to AzureRoleAssignmentResource. 3. Change EndpointReferenceAnnotation.EndpointNames from HashSet<string> to ISet<string> (backing field stays HashSet). 4. Add 'sealed' to new public resource classes that are not subclassed in the repo: KubernetesHelmChartResource, BlazorWasmAppResource, BunAppResource, NextJsAppResource, ViteAppResource, AzureNatGatewayResource, AzureNetworkSecurityGroupResource, AzureNetworkSecurityPerimeterResource, AzurePrivateEndpointResource, AzurePublicIPAddressResource, AzureSubnetResource, AzureVirtualNetworkResource. (GoAppResource and NodeAppResource left non-sealed because they are used as generic type constraints in the same assembly.) 5. Disambiguate WithHiddenOnCompletion overloads by removing the '= 0' default from the int overload, so calls with no argument resolve to the params overload. api/*.cs and api/*.ats.txt are intentionally not updated here - the API surface PR will regenerate them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert breaking API changes; bump baseline to 13.3.5 Reverts the subset of API changes from the previous commit that would be binary-breaking against 13.3.5, and bumps PackageValidationBaselineVersion from 13.2.2 to 13.3.5 so pack validation runs against the latest shipped release. Reverts (binary-breaking against 13.3.5): - AllocatedEndpoint.NetworkID (kept ctor param 'networkId' - not breaking) - EndpointAnnotation.DefaultNetworkID (kept ctor param 'networkId') - EndpointReference.ContextNetworkID (kept ctor param 'contextNetworkId') - NetworkEndpointSnapshot.NetworkID record positional param - Removed 'sealed' from 9 shipped resource classes: - NextJsAppResource, ViteAppResource - AzureNatGatewayResource, AzureNetworkSecurityGroupResource, AzureNetworkSecurityPerimeterResource, AzurePrivateEndpointResource, AzurePublicIPAddressResource, AzureSubnetResource, AzureVirtualNetworkResource Kept (not binary-breaking): - All constructor/method parameter renames (networkID->networkId, etc.) - EndpointReferenceAnnotation.ContextNetworkId (new in 13.4) - EndpointNames type change (HashSet -> ISet) - WithHiddenOnCompletion overload disambiguation - [Experimental("ASPIREAZURE003")] on AzureRoleAssignmentResource - 'sealed' on KubernetesHelmChartResource, BlazorWasmAppResource, BunAppResource (new in 13.4) Package validation: - Bumped PackageValidationBaselineVersion 13.2.2 -> 13.3.5 - Regenerated CompatibilitySuppressions.xml in 4 projects: most legacy entries against 13.2.2 are no longer needed because those APIs already shipped in 13.3.x. The remaining suppression is PublishAsNpmScript in Aspire.Hosting.JavaScript (documented removal from PR #17382). --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit da473d2) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add Foundry hosted agent protocol selection Support configuring Foundry hosted agent protocols for publish output and local run-mode dashboard commands, including TypeScript AppHost coverage for the exported DTO shape. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address Foundry hosted agent review feedback Improve hosted agent protocol validation parameter names and add run-mode context when configuration callbacks fail during protocol inference. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Sync Foundry hosted agent endpoint protocols Update hosted agent deployment to patch the Foundry agent endpoint protocols after creating a hosted-agent version, so endpoint routing matches the configured container protocol versions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Skip Foundry reserved hosted agent env vars Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit 9c260c2) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pe (#17743) * Route staging-identity CLI to its darc feed regardless of version shape The synthesized `staging` package channel derived its feed from the CLI build's version shape: a prerelease-shaped staging build (e.g. 13.4.0-preview.1.26280.6) routed Aspire.* to the shared dnceng/dotnet9 daily feed instead of its SHA-specific darc-pub-microsoft-aspire-<commit> feed. C# apphosts masked this because the darc feed is baked into their nuget.config, but polyglot (TypeScript) apphosts resolve solely through the channel's feed, so `aspire add <pkg>` offered the wrong versions. Decouple feed provenance (identity) from version filtering (quality): - Add `ShouldUseSharedStagingFeed(...)`: a staging-identity CLI always uses its own darc feed, any version shape. Override feeds and non-staging identities keep the prior quality-based routing. - Add an injectable `cliInformationalVersionProvider` constructor seam so the derived darc feed URL is deterministic and assertable in tests. - Correct the comments that incorrectly claimed darc feeds only exist for stable-shaped builds. Add tests covering prerelease-shaped staging -> darc, stable-shaped staging -> darc, and override-wins. The prerelease repro fails before the fix (resolves dotnet9) and passes after (resolves darc). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Strengthen staging feed-routing tests and warn on underivable feed Adds a decision-table theory across PR/daily/staging/stable channel configurations, drops the override-feed crutch from the staging-identity tests so they assert the real darc feed via an injected version seam, adds coverage for the underivable-feed warning path, and adds symmetry asserts for the stable-shaped staging case. Also logs a one-time warning in CreateStagingChannel when a staging channel is permitted but no staging feed URL can be derived, so the channel is omitted visibly instead of silently. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add diagnostic overrides to validate staging feed routing locally Adds two PackagingService-scoped diagnostic config overrides so a locally built CLI (baked identity 'local', unstamped version) can simulate a staging build and validate end-to-end that 'aspire add' resolves Aspire.* from the correct SHA-specific darc-pub-microsoft-aspire-<sha> feed: - overrideCliIdentityChannel: forces the identity used for staging-feed routing decisions only (validated via IdentityChannelReader.IsValidChannel; invalid values ignored). Does not change the global identity used for hive/packages-directory lookups, keeping blast radius limited. - overrideCliInformationalVersion: forces the version that both the SHA derivation and the stable-shape/quality predicate read. All staging-feed decision points now route through GetEffectiveIdentityChannel. A one-time warning is emitted whenever either override is active. Adds docs/cli-staging-validation.md with the local-validation recipe and nine PackagingServiceTests covering the override permutations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add debug-staging/debug-stable scripts to simulate release-branch feed routing Add eng/scripts/debug-staging.{sh,ps1} and debug-stable.{sh,ps1} (plus the shared debug-aspire-channel core) that make an easy-to-get build (an installed PR build or a local build) resolve Aspire.* packages exactly like an official staging or stable release-branch build, so the feed-routing fix can be validated end-to-end. Each script targets identity 'staging' and the SHA-specific darc-pub-microsoft-aspire-<sha8> feed, differing only in version shape/quality (staging => prerelease/Both, #17744; stable => stable/Stable, #17527). Modes: - default: one-shot 'aspire add --debug' that asserts the darc feed resolves. - --print-env / -PrintEnv: emit export/$env lines to apply to the current shell. - --shell / -Shell: interactive subshell with overrides applied and the target CLI first on PATH, for a full 'aspire new'/'add'/run flow; overrides vanish on exit. Extend docs/cli-staging-validation.md with the helper-script usage, the interactive PR-build recipe, and a validation matrix; link it from docs/contributing.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Isolate NuGet package cache in debug-channel --shell mode When dropping into the interactive subshell (--shell / -Shell), point NUGET_PACKAGES at an isolated, per-sha directory so packages restored from the simulated staging darc feed can never contaminate the developer's real global package cache. Also commit the staging-override NOTE clarifying the overrides route to but do not create a feed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix staging-identity update test for identity-driven darc feed routing The staging identity now always routes to its build's SHA-specific darc-pub-microsoft-aspire-<sha> feed regardless of version shape, so the feed must be derivable from the CLI's +<commit> informational version. The test host assembly has no commit metadata, so the staging channel could not be synthesized and the test regressed. Stamp a staging-shaped informational version via the overrideCliInformationalVersion config so the derivation matches a real staging build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit e138509) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ted agents (#17756) * Resolve cross-compute-environment endpoint references to Foundry hosted agents Fixes #17749. When a resource deployed to App Service, Azure Container Apps, or Kubernetes used WithReference() to reference a Foundry hosted agent, publishing failed because the publisher resolved the endpoint against its own local endpoint map, which does not contain the agent (deployed to the Foundry project compute environment). Introduce a shared ComputeEnvironmentEndpointResolver that, when an endpoint's owning resource is deployed to a different compute environment than the current publisher, delegates resolution to that owning environment's GetEndpointPropertyExpression. The three compute-environment publishers now call it in both the EndpointReference and EndpointReferenceExpression branches. Azure Front Door and the Foundry hosted-agent resolver are refactored onto the same shared lookup. AzureCognitiveServicesProjectResource gets a GetEndpointPropertyExpression override because the agent address is already a full https URL; the default scheme://host composition would produce a malformed double-scheme value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add branch tests for ComputeEnvironmentEndpointResolver and correct misleading comment Add direct unit tests covering each branch of TryGetCrossEnvironmentEndpointExpression: cross-environment delegation, same-environment deployment target, WithComputeEnvironment binding backstop, no-compute-environment, bound multi-target (no throw), and unbound multi-target (throws). Correct the comment on the fast-path loop which incorrectly claimed it never throws on multi-target resources. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove redundant fast-path loop from ComputeEnvironmentEndpointResolver The first foreach loop using GetDeploymentTargetAnnotation(current) was redundant with TryGetEffectiveComputeEnvironment + the ReferenceEquals backstop for all well-formed inputs, and did not provide multi-target throw-safety. Remove it and keep the simpler resolve-then- compare flow. All six branch tests continue to pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Drop params and move out parameter last in cross-env endpoint resolver Replace the params IComputeEnvironmentResource?[] with an explicit IReadOnlyList parameter placed before the out, so the out parameter comes last per convention. Kubernetes still passes two current environments (its environment plus OwningComputeEnvironment) via a collection expression; ACA and AppService pass a single-element list. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add EndpointReference overload for cross-env endpoint resolver Add an overload taking EndpointReference that uses ep.Property(EndpointProperty.Url) internally, so the three EndpointReference call sites (ACA, AppService, Kubernetes) pass the endpoint directly instead of repeating the .Property(Url) projection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use hosted-agent deployment name in cross-env Foundry agent URL Hosted-agent deployment creates the Foundry agent version using the wrapper AzureHostedAgentResource.Name (e.g. "agent-ha" for a target named "agent"). The published cross-environment endpoint path was built from the bare resource name, producing /agents/agent which does not match the deployed /agents/agent-ha. Resolve the hosted-agent deployment target and use its name when present, falling back to the resource name for non-hosted agents. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Auto-wire Azure AI User role for hosted-agent consumers When a compute resource references a Foundry hosted agent's node app via WithReference, automatically grant the consumer the Azure AI User role on the owning Foundry account and provision a managed identity, removing the two manual post-deploy `az role assignment create` steps. Introduces a public, experimental ReferenceRoleAssignmentAnnotation in Aspire.Hosting.Azure. A resource that "fronts" an Azure resource (without being an IAzureResource itself) carries this annotation; AzureResourcePreparer folds its (Target, Roles) into the same role-assignment path used for direct Azure references. Foundry's AsHostedAgent stamps the annotation on the agent's node app granting only the least-privilege Azure AI User role; account defaults and explicit WithRoleAssignments suppression remain owned by the preparer and are not reintroduced. GetAllRoleAssignments now dedupes roles per target to avoid colliding bicep role-assignment identifiers. Adds preparer end-to-end tests (suppression preserved, defaults preserved, dedup) and Foundry stamp tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Regenerate cross-env Foundry snapshots for RBAC auto-wiring The cross-compute-environment Foundry hosted-agent snapshots were committed before the RBAC auto-wiring change and never regenerated. With the consumer now receiving a managed identity (web-identity) plus AZURE_CLIENT_ID and AZURE_TOKEN_CREDENTIALS env vars, the generated bicep/json changed. CI failed because the verified baselines were stale; local runs masked it because Verify auto-accepts on developer machines. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit becb48e) 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 -- 17775Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17775" |
Update the extension contributor guide after removing Corepack from the build scripts so setup, install, test, and Yarn-version instructions use the direct Yarn flow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove stale references to extension build entrypoints and contributor Corepack instructions after the build scripts moved to direct Yarn. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
❓ CLI E2E Tests unknown — 110 passed, 0 failed, 2 unknown (commit View all recordings
📹 Recordings uploaded automatically from CI run #26736168859 |
|
Jose Perez Rodriguez (@joperezr) ready to merge this? Would be good to get some of the late changes made on 13.4 back into main so we can start iterating on fixes for some of the staging/stable issues for 13.5. |
|
We shouldn't merge this. The correct way to forward port is to merge the release branch back to main, which is a process that is already started. Let's close this one and I'll handle the other one where O'm fixing merge conflicts. |
Jose Perez Rodriguez (joperezr)
left a comment
There was a problem hiding this comment.
Handling this in a separate PR that actually merges the branches to forward port and have the preserved commit ids.
The merge auto-pulled release/13.4's api/*.cs and api/*.ats.txt baselines for 56 pre-existing
packages. These baselines no longer match main's source code (e.g., Foundry's source has
[AspireExport("asHostedAgent")] from #17671 but the release baseline says "asHostedAgentExecutable",
and the release baseline still references the WithComputeEnvironment method that was renamed to
the AsHostedAgent overloads in #17732).
Per repo convention (.github/copilot-instructions.md): api files are regenerated as part of the
release process, not during individual PRs. Reverting to main's state matches what @davidfowl's
forward-port PR #17775 does, and lets the next release run regenerate them.
The 2 net-new api files for the new Aspire.Hosting.Blazor and Aspire.Hosting.Go integrations
are kept as-is (they didn't exist on main).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description
Forward-ports the release-only fixes from
release/13.4that were not present onmain, preserving the original cherry-pick metadata for traceability.Forward-ported commits
6a8235582- Fix 13.4 staging CLI dropping nuget.config without Aspire package source mapping (Fix 13.4 staging CLI dropping nuget.config without Aspire package source mapping #17528)3f0998a95- Prefer current CLI template version for aspire new (Prefer current CLI template version for aspire new #17564)5d0da8b9- Stabilize PrebuiltAppHostServer staging globalPackagesFolder path ([release/13.4] Stabilize PrebuiltAppHostServer staging globalPackagesFolder path #17573)a0823e66- Remove Corepack from extension build scripts ([release/13.4] Remove Corepack from extension build scripts #17628)26b661bd- Forward IdentityChannel to TemplateInputs.Channel for dotnet-runtime templates (Forward IdentityChannel to TemplateInputs.Channel for dotnet-runtime templates #17637)d8c4e964- Removeaspire new aspire-starterstep from CLI archive verifier ([release/13.4] Remove 'aspire new aspire-starter' step from CLI archive verifier #17646)e258349f- Handle process inspection race during shutdown (Handle process inspection race during shutdown #17676)dfd226a4- Mark Aspire.Hosting.Blazor as preview ([release/13.4] Mark Aspire.Hosting.Blazor as preview #17694)56e88661- Restore implicit-channel discovery and guard non-interactive fuzzy auto-pick (fix(cli): restore implicit-channel discovery + guard non-interactive fuzzy auto-pick (#17724, #17725) #17728)da473d27- API review fixes for 13.4 (API review fixes for 13.4 (PR #17700) #17706)9c260c29- Add Foundry hosted agent protocol selection (Add Foundry hosted agent protocol selection #17732)e1385099- Route staging-identity CLI to its darc feed regardless of version shape (Route staging-identity CLI to its darc feed regardless of version shape #17743)becb48e2- Resolve cross-compute-environment endpoint references for Foundry hosted agents (Resolve cross-compute-environment endpoint references for Foundry hosted agents #17756)This also includes two self-review cleanup commits (
7510e819d,eb5c6734f) that align the extension contributor docs and Corepack bootstrap comments with the direct Yarn build flow introduced by #17628.The included fixes cover:
aspire new aspire-starterCLI archive verifier step.Aspire.Hosting.Blazoras preview for 13.4.Security considerations
This forward-port includes the
release/13.4Foundry hosted-agent fix that auto-wires the least-privilege Azure AI User role for hosted-agent consumers and provisions managed identity metadata for those consumers. This PR does not introduce additional security behavior beyond the already-merged release fixes, but reviewers should treat the RBAC wiring and cross-compute-environment endpoint resolution as the security-relevant parts of the change.Validation:
./restore.sh./build.sh --build /p:SkipNativeBuild=true./dotnet.sh test --project tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-build --no-launch-profile -- --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"./dotnet.sh test --project tests/Aspire.Hosting.Foundry.Tests/Aspire.Hosting.Foundry.Tests.csproj --no-build --no-launch-profile -- --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"./dotnet.sh test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-build --no-launch-profile -- --filter-class "*.ComputeEnvironmentEndpointResolverTests" --filter-class "*.EndpointReferenceTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"./dotnet.sh test --project tests/Aspire.Hosting.Azure.Tests/Aspire.Hosting.Azure.Tests.csproj --no-build --no-launch-profile -- --filter-method "*.EndpointReferenceToFoundryHostedAgentIsResolvedAcrossComputeEnvironments" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet pack src/Aspire.Hosting/Aspire.Hosting.csproj --no-restore /p:SkipNativeBuild=truedotnet pack src/Aspire.Hosting.JavaScript/Aspire.Hosting.JavaScript.csproj --no-restore /p:SkipNativeBuild=truedotnet pack src/Aspire.Hosting.Azure.Network/Aspire.Hosting.Azure.Network.csproj --no-restore /p:SkipNativeBuild=truegit --no-pager diff --checkAttempted
tests/Aspire.Acquisition.TestsforVerifyCliArchivePowerShellTests, but the local machine does not havepwsh; the class is gated byRequiresTools(["pwsh"]), so MTP discovered zero tests locally.Fixes # (issue)
Checklist
<remarks />and<code />elements on your triple slash comments?