Add Rust hosting package and VS Code debugger wiring - #18906
Conversation
Implements Rust AppHost hosting resources, playground wiring, and VS Code extension debug adapter support for Rust resources. Co-authored-by: Copilot App <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 -- 18906Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18906" |
There was a problem hiding this comment.
Pull request overview
Adds first-class Rust hosting, publishing, playground, and VS Code debugging support to Aspire.
Changes:
- Adds Rust and Bacon resource APIs with Cargo configuration and container publishing.
- Adds Rust playgrounds and hosting tests.
- Integrates Rust debugger detection and launch configuration into the VS Code extension.
Reviewed changes
Copilot reviewed 30 out of 32 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
src/Aspire.Hosting.Rust/Aspire.Hosting.Rust.csproj |
Defines the Rust hosting package. |
src/Aspire.Hosting.Rust/BaconAppResource.cs |
Models Bacon-managed Rust applications. |
src/Aspire.Hosting.Rust/PackageInfo.cs |
Supplies package metadata. |
src/Aspire.Hosting.Rust/README.md |
Introduces package documentation. |
src/Aspire.Hosting.Rust/RustAnnotations.cs |
Defines Cargo configuration annotations. |
src/Aspire.Hosting.Rust/RustAppResource.cs |
Models Cargo-based Rust applications. |
src/Aspire.Hosting.Rust/RustCargoArgsCallbackContext.cs |
Exposes deferred Cargo argument configuration. |
src/Aspire.Hosting.Rust/RustHostingExtensions.cs |
Implements hosting, publishing, and debugging APIs. |
src/Aspire.Hosting.Rust/RustLaunchConfiguration.cs |
Defines DCP Rust launch metadata. |
src/Aspire.Hosting.Rust/RustVersionDetector.cs |
Reads pinned Rust toolchain versions. |
src/Aspire.Hosting/Aspire.Hosting.csproj |
Grants Rust projects internal hosting access. |
tests/Aspire.Hosting.Rust.Tests/Aspire.Hosting.Rust.Tests.csproj |
Defines the Rust hosting test project. |
tests/Aspire.Hosting.Rust.Tests/RustPublicApiTests.cs |
Tests resource APIs and Cargo arguments. |
playground/rust/Cargo.toml |
Defines the Rust AppHost crate. |
playground/rust/app/Cargo.toml |
Defines the sample Rust service. |
playground/rust/app/src/main.rs |
Implements the sample HTTP service. |
playground/rust/apphost.rs |
Provides the Rust AppHost entrypoint. |
playground/rust/aspire.config.json |
Configures the polyglot playground. |
playground/rust/src/main.rs |
Defines the Rust application model. |
playground/rust-apphost/AppHost.cs |
Adds a C# Rust-hosting playground. |
playground/rust-apphost/rust-apphost.csproj |
Defines its AppHost project. |
Aspire.slnx |
Registers the new package, tests, and playground. |
extension/src/debugger/languages/rust.ts |
Generates Rust debug configurations. |
extension/src/debugger/languages/index.ts |
Registers Rust debugger handling. |
extension/src/debugger/debuggerExtensions.ts |
Adds Rust debugger extension identifiers. |
extension/src/capabilities.ts |
Advertises available Rust debug adapters. |
extension/src/test/rustDebugger.test.ts |
Tests Rust configuration translation. |
extension/src/test/capabilities.test.ts |
Tests Rust capability detection. |
extension/src/loc/strings.ts |
Adds localized Rust capability text. |
extension/package.nls.json |
Adds Rust localization resources. |
extension/loc/xlf/aspire-vscode.xlf |
Updates generated translation data. |
extension/package.json |
Declares Rust debugger extension dependencies. |
Comments suppressed due to low confidence (1)
extension/src/debugger/languages/rust.ts:73
- The C++ adapter path never invokes Cargo: this branch removes
cargo, pointsprogramat a presumed output file, and the caller immediately starts the debug session. On a clean checkouttarget/...does not exist, socppvsdbg/cppdbglaunch fails even though these adapters are advertised as supported. Add a build/task step before launching, or do not expose these adapters until that flow exists.
if (debugAdapter === 'cppvsdbg' || debugAdapter === 'cppdbg') {
debugConfiguration.program = getRustBinaryPath(launchConfig);
delete debugConfiguration.cargo;
return;
- Move AppHost to project rather than file based app - Get Debugging working
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 32 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (13)
playground/rust/aspire.config.json:3
- This configuration declares a Rust AppHost but points at the C# project. The Rust entry point at
apphost.rsis therefore never selected, and the guest-host pipeline will try to treat the.csprojas Rust input. Point this atapphost.rs(or change the language to C# if the C# AppHost is intended).
"path": "Rust.AppHost/Rust.AppHost.csproj",
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:105
- The generated Dockerfile assumes the Cargo binary name equals the Aspire resource name. That is not a Cargo invariant, and the included sample already demonstrates the failure: the resource is named
app, while Cargo buildsaspire-sample-rust-app, so thisCOPYcannot find the executable. Resolve the default binary target from Cargo metadata/the manifest, while preservingWithCargoBinTargetas the explicit override.
.CopyFrom("build", $"/app/target/release/{binaryName}", $"/app/{binaryName}")
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:98
- Publish mode discards the Cargo configuration applied by
WithCargoFeaturesand other Cargo-argument APIs: local run/debug uses those annotations, but the generated image always executes onlycargo build --release. Feature-gated binaries can therefore run locally and then fail or produce different output when published. Build the publish command from the supported Cargo options (at minimum features and binary target) and add a generated-Dockerfile regression test.
.Run("cargo build --release");
src/Aspire.Hosting.Rust/RustVersionDetector.cs:16
- This regex is not a TOML parser and can select a commented-out
channelbefore the active value. In addition, the legacyrust-toolchainfilename may contain the same[toolchain]TOML form, but lines 26-29 return that whole file as an image tag. Parse both supported formats while honoring TOML comments/strings so generatedFROMreferences are valid.
var content = File.ReadAllText(toolchainTomlPath);
var match = ChannelRegex().Match(content);
src/Aspire.Hosting.Rust/README.md:5
- This scaffold README is being packaged as the integration's user documentation, but it does not explain how to install or use the new resource. Replace it with the standard hosting-integration README: Rust title/description, prerequisites, exact
aspire add Aspire.Hosting.Rustcommand, minimal C# and generated polyglot usage, additional documentation, and the feedback section.
# Aspire.Hosting.Rust
Rust support for Aspire hosting integrations.
## Status
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:82
- The new generated-Dockerfile path has no publish-mode coverage; the added Rust tests only evaluate run arguments. Add a publish test that snapshots the Dockerfile and covers toolchain selection, differing resource/Cargo binary names, Cargo feature/bin options, and the existing-Dockerfile path. Comparable coverage exists in
tests/Aspire.Hosting.Go.Tests/AddGoAppTests.cs:725-845.
.PublishAsDockerFile(containerBuilder =>
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:53
- These new exports are not exercised by the repository's polyglot validation. There is no
tests/PolyglotAppHosts/Aspire.Hosting.Rustfixture, andeng/github-ci/test-trigger-map.yml:340-350does not include the new project in the polyglot job. Add a fixture that compiles the generated calls and update the trigger so changes to this exported surface run it; the playground is not CI validation.
[AspireExport]
extension/src/debugger/languages/rust.ts:149
- The tests stub
IRustService, so none of the user-visible debugger flow is exercised through DCP metadata, a real Cargo build, executable discovery, or either platform adapter. Add VS Code extension E2E coverage for a Rust resource, including the platform-specific adapter selection and a build failure; the PR itself notes macOS/Linux has not been validated.
createDebugSessionConfigurationCallback: async (launchConfig, args, _env, launchOptions, debugConfiguration: AspireResourceExtendedDebugConfiguration): Promise<void> => {
playground/rust/app/src/main.rs:23
- The hosting integration automatically publishes this executable as a container, but the sample binds only to container loopback. Its declared HTTP endpoint and health check will be unreachable from outside the container after publish/deploy. Bind the sample to all container interfaces.
let address = SocketAddr::from(([127, 0, 0, 1], port));
extension/src/debugger/languages/rust.ts:98
rustBuildFailedWithExitCodeexpects an exit code, but this passes the entire stderr stream whenever stderr is nonempty. Users then receive an error claiming the compiler output is the exit code, while the actual code is omitted. Passcodehere; stderr is already streamed to the debug console.
This issue also appears on line 149 of the same file.
reject(new Error(rustBuildFailedWithExitCode(workingDirectory, stderrOutput || `${code}`)));
extension/src/loc/strings.ts:155
- This user-facing error names the C# API, but Rust and TypeScript AppHosts receive different generated method names. A Rust AppHost user cannot call
WithCargoBinTarget. Keep the message language-neutral so it is actionable for every supported AppHost language.
export const rustBuildProducedNoExecutable = (workingDirectory: string) => vscode.l10n.t('cargo build in {0} completed but did not produce a runnable binary. Ensure the crate defines a binary target, or select one with WithCargoBinTarget.', workingDirectory);
src/Aspire.Hosting.Rust/Aspire.Hosting.Rust.csproj:8
- This package exports ATS APIs, but integration analyzers are disabled by default in
Aspire.Hosting.targets. Without opting in, invalid generated-SDK shapes are not validated and the package also misses the automaticpolyglotpackage tag used for non-C# discovery. Enable the integration analyzers for this project.
<SuppressFinalPackageVersion>true</SuppressFinalPackageVersion>
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:49
- The primary public extension method lacks the required behavioral documentation for a new language integration. Add
<remarks>covering local Cargo execution versus generated-Dockerfile publish behavior, an<example>with a working AppHost call, and documentation for the validation exceptions so IntelliSense and published API docs describe this API accurately.
This issue also appears in the following locations of the same file:
- line 53
- line 82
/// <summary>
/// Adds a Rust application to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/> to add the resource to.</param>
/// <param name="name">The name of the resource.</param>
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
The generated publish Dockerfile could not build a working container:
- The binary copied out of the build stage was named after the Aspire resource
rather than the cargo target, so `AddRustApp("app", ...)` emitted
`COPY target/release/app` while cargo produced `aspire-sample-rust-app`. The
target is now resolved from Cargo.toml, preserving hyphens (only library
targets translate `-` to `_`). Crates with several `[[bin]]` targets must
select one with WithCargoBinTarget.
- Rustup channel names were used directly as image tags, producing tags that do
not exist (`rust:stable-alpine`, `rust:nightly-alpine`). `stable` now maps to
`rust:alpine`; `beta` and `nightly` have no official image and throw with a
message pointing at WithDockerfileBaseImage. Patch-level pins such as
`1.89.0` are preserved verbatim.
- The toolchain regex matched commented TOML, so `# channel = "nightly"` could
win over the real value. Parsing is now line-oriented and comment-aware.
- Cargo arguments configured via WithCargoArgs/WithCargoFeatures were discarded
at publish time, so the container was built from a different command line than
local execution. All arguments are now forwarded and shell-quoted, and the
`COPY --from` path follows the selected profile.
- Alpine build images ship no C toolchain, so crates with native dependencies
(ring/aws-lc via rustls, anything using cc) failed to link. musl-dev and gcc
are installed when the build image is Alpine.
- Honour the shared DockerfileBaseImageAnnotation, matching Aspire.Hosting.Go,
so callers can supply their own build and runtime images. The Alpine-only
hardening steps (apk, BusyBox adduser, USER) are emitted only for Alpine
runtime images; previously they were unconditional and produced a Dockerfile
that could never build on, for example, debian:bookworm-slim.
Verified end to end: the playground publishes, the image builds, and the
container serves requests as a non-root user.
The playground sample bound to 127.0.0.1, which is unreachable once
containerised, so it now binds 0.0.0.0 as the Go samples do.
Also replaces the README scaffold with the standard hosting integration
structure covering the public API surface.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 46 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (11)
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:145
WithCargoArgs("--target", "x86_64-unknown-linux-musl")writes the binary undertarget/<triple>/<profile>/, but this COPY always readstarget/<profile>/. The generated image therefore fails to build for a valid cross-compilation configuration. Parse the selected target (and target-directory overrides) when resolving the artifact path, or obtain the artifact path from Cargo metadata.
.CopyFrom("build", $"/app/target/{profileDirectory}/{binaryName}", $"/app/{binaryName}");
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:124
RustAppResourceadvertisesIContainerFilesDestinationResource, soPublishWithContainerFilescan attach file sources, but this generated Dockerfile never emits their build stages or runtime copies. Those files are silently absent from the published image. Mirror theAddContainerFilesStages/AddContainerFileshandling used byAspire.Hosting.Go(GoHostingExtensions.cs:276-305).
buildStage
.Copy(".", ".")
.Run(BuildCargoCommand(cargoArgs));
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:487
- A rustup channel may be a version plus host triple, for example
1.89.0-x86_64-unknown-linux-gnu. This branch treats it as a plain version and generates the nonexistent tagrust:1.89.0-x86_64-unknown-linux-gnu-alpine. Parse versioned toolchain names or reject host-qualified channels with the existing base-image override guidance.
return $"rust:{channel}-alpine";
extension/src/debugger/languages/rust.ts:98
- When Cargo writes anything to stderr—which it normally does on failure—
stderrOutputis passed as the{exitCode}placeholder. Users receive a multiline diagnostic labeled as an exit code instead of the actual code. The stderr has already been streamed to the debug console, so passcodehere.
reject(new Error(rustBuildFailedWithExitCode(workingDirectory, stderrOutput || `${code}`)));
src/Aspire.Hosting.Rust/README.md:1
- The required hosting README title is
# {Technology} hosting integration; adding “app” makes this inconsistent with the integration README contract.
# Rust app hosting integration
src/Aspire.Hosting.Rust/README.md:36
- The hosting README usage example must demonstrate the resource-reference flow, but both samples stop after creating the Rust app. Add a dependent resource and call
WithReference(api)/withReference(api)so users can see how Rust endpoints participate in the AppHost model.
var api = builder.AddRustApp("api", "../rust-api")
.WithHttpEndpoint(env: "PORT")
.WithExternalHttpEndpoints()
.WithOtlpExporter();
extension/src/debugger/languages/rust.ts:80
- An unfiltered workspace or crate with multiple binaries reaches this assignment multiple times, so the debugger silently launches whichever compiler artifact Cargo reports last. That order is not a target-selection contract and differs from
cargo run, which requires a binary selection. Track matching artifacts and reject an ambiguous build with guidance to useWithCargoBinTarget.
This issue also appears on line 98 of the same file.
if (artifact.executable && artifact.target?.kind?.includes('bin') && (!filter || artifact.target?.name === filter)) {
executablePath = artifact.executable;
src/Aspire.Hosting.Rust/RustCargoArgsCallbackAnnotation.cs:44
- This public list accepts arbitrary argument objects, but only run mode resolves
IValueProvidervalues. Debugging silently drops non-strings viaOfType<string>(), while publishing callsToString(), so the same callback has different arguments in each mode. Either make Cargo arguments explicitlyIList<string>or use a shared value-resolution path across run, debug, and publish.
/// <summary>
/// Gets the list of command-line arguments.
/// </summary>
public IList<object> Args { get; } = args ?? throw new ArgumentNullException(nameof(args));
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:42
AddBaconAppremains anexecutable.v0running the development watcher during publish, unlikeAddRustApp, which becomes a container. This leaks dev-only watch behavior into publish output and leaves the workload undeployable on container targets. Either make Bacon run-only and exclude it from manifests, or reuse the Rust container publish path while keeping Bacon only for local run mode.
This issue also appears in the following locations of the same file:
- line 122
- line 145
return builder.AddResource(resource)
.WithArgs("run")
.WithRequiredCommand("bacon", "https://dystroy.org/bacon/")
.WithRustDefaults();
extension/src/debugger/languages/rust.ts:155
- The new debugger flow has only unit tests that replace
RustServicewith a stub, so they never exercise Cargo JSON parsing, process failures, executable selection, environment transfer, or either native adapter. Add VS Code extension E2E coverage that builds a real crate and starts the supported adapter; the PR description currently confirms only Windows was manually tested.
const rustService = rustServiceProducer(launchOptions.debugSession);
const executablePath = await rustService.buildAndGetExecutablePath(workingDirectory, cargoArgs, config.cargo?.filter);
src/Aspire.Hosting.Rust/RustHostingExtensions.cs:82
- The publish tests only snapshot Dockerfile text; none builds and runs the generated image. For a new language publish path, this misses linker/runtime compatibility, artifact-path correctness, entrypoint behavior, and endpoint binding. Add a functional publish/deployment test that builds the Rust image, starts it, and probes the sample endpoint.
.PublishAsDockerFile(containerBuilder =>
|
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: 1f541574-f58e-4d6d-8b84-16927f933faa
…etry helpers from AppHostLaunchService
… layer from the policy service
…gger extension gate, stopped-AppHost lens
…ck-file boundary, pipeline wiring, app user, bin target
# Conflicts: # src/Aspire.Cli/Packaging/PackageChannel.cs # src/Aspire.Cli/Packaging/PackageSourceOverrideMappings.cs
…the packages-override guard recursive `PackageChannel.GetTemplatePackagesAsync(workingDirectory, mappings, ct)` selected the local Aspire directory from the channel's own mappings, so a caller-supplied override (`aspire new --source <dir>`) was silently ignored for unpinned explicit channels and templates were listed from the channel's directory instead. Thread the supplied mappings through local-source selection. This also routes a local `--source` directory through direct enumeration, which — unlike `dotnet package search` — sees hierarchical local feeds. `PackagingService.EnsurePackagesOverrideDirectoryIsUnambiguous` enumerated only top-level `Aspire*.nupkg` while local package discovery walks `SearchOption.AllDirectories`, so duplicate versions in nested directories bypassed the fail-fast guardrail. Enumerate recursively so the guard matches discovery. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b93d5546-f35d-4ce0-832b-afe34ed14486
…y detection Two fixes in the extension's CLI runner: - `runCliCommand` added the spawned handle to `_oneShotProcesses` after `spawnCliProcess` returned. When the spawn reported completion synchronously, `settle` ran before the local was assigned, so it removed nothing and the already-exited process stayed tracked for the lifetime of the runner. Guard the tracking the same way `AppHostPsPoller` does, and terminate the handle if a cancellation or timeout raced the spawn. - `isDescribeUnsupportedOutput` matched any "unrecognized command/option" wording anywhere in the output, so a current CLI reporting a user-supplied option (for example an AppHost that rejects `--publisher`) was misreported as a CLI too old to `describe`, replacing the real error with an upgrade banner and marking it a CLI-wide compatibility failure. Detection is now per line and scoped to the tokens the extension itself passes, and a line quoting an option we never sent no longer counts. Old-CLI shapes (quoted or bare rejected token, localized rejection text, top-level help) still trigger the fallback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b93d5546-f35d-4ce0-832b-afe34ed14486
…rbofish parsing
Three small extension fixes:
- `rustDebuggerExtensionNotInstalled` existed in `loc/strings.ts` but had no
`package.nls.json` entry, so it never reached the XLF catalog and shipped
untranslated. Added the entry and regenerated `loc/xlf/aspire-vscode.xlf`
with `yarn run localize`.
- `aspire-vscode.codeLensRevealAppHost` is registered and used by the CodeLens
provider, but unlike every peer CodeLens command it was missing from
`contributes.commands` and from the hidden `commandPalette` list.
- The Rust parser only recognized a bare `field_expression`, so valid calls with
a turbofish (`builder.add_project::<Frontend>("web")`) parse as
`generic_function` and were silently skipped. Unwrap that node before reading
the `add_*` field name.
Each fix has a regression test: an nls/XLF parity check for the rust strings, a
manifest check that every registered CodeLens command is contributed and hidden
from the palette, and parser tests for turbofished `add_*` calls plus the
receiverless negative shape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b93d5546-f35d-4ce0-832b-afe34ed14486
…gs callbacks their resource Two independent fixes to the Rust hosting integration. Aspire.Hosting.Rust reached PathNormalizer through a product-to-product InternalsVisibleTo entry in Aspire.Hosting.csproj. No sibling integration does that: JavaScript, Dotnet, and Maui all source-share src/Shared/PathNormalizer.cs and build against the public Aspire.Hosting surface only. Drop the IVT and add the same $(SharedDir) Compile Link item to the Rust project. That leaves Aspire.Hosting.Rust.Tests seeing two equally accessible Aspire.Hosting.Utils.PathNormalizer types (it still needs Aspire.Hosting's internals for Dcp.Model), which is CS0433 at every use site. Add a TestPathNormalizer forwarder to Aspire.Hosting.TestUtilities so tests can name the one shared implementation, rather than duplicating it or suppressing the conflict. RustCargoArgsCallbackContext also carried no reference to the resource being configured, so a callback could not read annotations or other resource state without capturing the resource from the enclosing scope. Add a strongly typed Resource property and make it a required constructor parameter — it has no sensible default — then pass it from both production construction sites, the run-mode WithArgs pipeline and the publish-mode Dockerfile generator. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b93d5546-f35d-4ce0-832b-afe34ed14486
The Rust runtime spec launches an AppHost with `cargo run --bin apphost --`
(AppHostBinaryName in RustLanguageSupport), and the scaffolded Cargo.toml
declares that `[[bin]]`. The playground named its binary
`rust-apphost-playground`, so the real launch path failed before it started:
$ cargo run --bin apphost -- --help
error: no bin target named `apphost` in default-run packages
Rename the bin target to `apphost` to match what the runtime and every
generated AppHost assume. The package name is left alone; only the target
name is part of the launch contract.
The manifest also carried direct `opentelemetry-otlp` and `tonic`
dependencies. Nothing in the AppHost uses them: apphost.rs only calls the
generated SDK, and the generated SDK (.aspire/modules) imports std, serde,
serde_json and lazy_static only. Telemetry belongs to the sample app under
./app, which declares those crates itself. Removing them prunes 146
transitive packages from the lockfile with no version changes to what
remains.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b93d5546-f35d-4ce0-832b-afe34ed14486
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
… behavior
The extension package-surface E2E hard-codes the contributed Aspire command
list, so adding aspire-vscode.codeLensRevealAppHost to package.json broke the
deepStrictEqual on Linux and Windows. Add it to the expected list and to the
hidden command-palette check, since CodeLens commands are invoked from lenses
and must not leak into the palette.
The source-override CLI E2E asserted `dotnet package search` diagnostics that
no longer exist: a local `--source` directory is now enumerated directly, and
`dotnet new install` is pointed at the .nupkg inside source-feed instead of a
feed plus `--nuget-source`. Assert the install argument list (temp-directory
suffixes are random, so match the args rather than the generated path).
Keep the core guarantee by rejecting the feed-backed template search the CLI
under test would actually run. CI installs a bundle, so that path is
BundleNuGetPackageCache -> `aspire-managed nuget search`, whose only trace is
its two Debug lines ("Running NuGet search via aspire-managed: ..." and
"NuGet search args: nuget search --query ..."); both the helper process and
the SDK-backed `dotnet package search` fallback are spawned with
SuppressLogging, so a guard on a logged `package search` command line could
never fail. Reject those lines alongside `--nuget-source`, api.nuget.org, and
the TCP tripwire.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b93d5546-f35d-4ce0-832b-afe34ed14486
Description
This adds first-party Rust hosting support and VS Code support for both Rust resources and Rust AppHosts.
The new
Aspire.Hosting.Rustintegration models Cargo applications, separates Cargo arguments from application arguments, resolves Cargo targets for debugging and publishing, and exports the APIs to C# and polyglot AppHosts.aspire publishandaspire deploygenerate a multi-stage Dockerfile when the app does not provide one.The VS Code extension can now discover, run, and debug
apphost.rsfiles and debug Rust resources from any AppHost. It uses Tree-sitter to locate Rust AppHost resources, selects CodeLLDB on macOS/Linux or C/C++ on Windows, and warns that rust-analyzer's adjacent Run and Debug actions launch Cargo directly and bypass Aspire.Changes vs Community Toolkit
Existing implementation: source | example
WithCargoArgs(...)andWithArgs(...)paths, following the direction in Resources with multiple args #18904.Publish support
The generated Dockerfile:
rust:1.97-alpine3.24for the build stage andalpine:3.24for the runtime stage by default. Arust-toolchain.tomlpin is installed with rustup inside the build image.appuser.WithCargo*options for target and binary resolution. RawWithCargoArgs(...)values are forwarded to Cargo and are not parsed again.Rust OTLP and TLS setup
Aspire provides the OTLP endpoint and development certificate environment variables. The Rust application still needs to enable the transport and TLS features required by its OpenTelemetry SDK and load native trust roots when using the development certificate. The
AddRustAppAPI remarks document that boundary, and the Rust playground demonstrates the application-side setup.Testing
Remaining cross-language test gaps
These gaps already apply to the other language integrations and are tracked separately:
PublishAsDockerFileoutput in outerloop tests: Add outerloop E2E tests that actually build and run PublishAsDockerFile output #19038Checklist
<remarks />and<code />elements on your triple slash comments?