Skip to content

aspire-managed unified binary + native certificate management#14441

Merged
mitchdenny merged 2 commits intorelease/13.2from
davidfowl/aspire-managed
Feb 24, 2026
Merged

aspire-managed unified binary + native certificate management#14441
mitchdenny merged 2 commits intorelease/13.2from
davidfowl/aspire-managed

Conversation

@davidfowl
Copy link
Member

@davidfowl davidfowl commented Feb 11, 2026

Summary

Consolidates the Aspire bundle managed components into a single self-contained binary (aspire-managed) and moves HTTPS certificate management natively into the CLI.

What changed

1. aspire-managed unified binary (src/Aspire.Managed/)

Single self-contained executable replacing 3 separate managed binaries + shared .NET runtime:

aspire-managed dashboard [args...]   # Aspire Dashboard
aspire-managed server [args...]      # AppHost Server (RemoteHost)
aspire-managed nuget [args...]       # NuGet search/restore/layout
  • References Dashboard, RemoteHost, and NuGetHelper as project references
  • Publishes as single-file self-contained (no separate runtime/ directory needed)
  • Zero changes to the referenced projects dispatches to their entry points

2. Native certificate management (src/Aspire.Cli/Certificates/CertificateGeneration/)

Ported ASP.NET Core CertificateManager library directly into the native AOT CLI:

  • Vendored 8 files from aspnetcore/src/Shared/CertificateGeneration/
  • Replaced EventSource (AOT-incompatible) with ILogger
  • Removed statics: CertificateManager.Create(ILogger) factory + instance Log property
  • NativeCertificateToolRunner calls CertificateManager directly no subprocess spawn
  • Deleted BundleCertificateToolRunner and SdkCertificateToolRunner

3. Bundle layout simplification

Before: runtime/ + dashboard/ + aspire-server/ + tools/aspire-nuget/ + tools/dev-certs/ (~172 MB across 5 directories)

After: managed/aspire-managed (~65 MB single binary including .NET runtime)

Certificate management is native to the CLI no external tool needed.

4. CreateLayout + Bundle.proj updates

  • Simplified to build aspire-managed + copy DCP (no SDK download/extraction step)
  • Updated layout.json schema: managed replaces runtime, dashboard, apphostServer, nugetHelper, devCerts
  • ASPIRE_MANAGED_PATH replaces ASPIRE_DASHBOARD_PATH and ASPIRE_RUNTIME_PATH

Smoke test results

Scenario Result
aspire doctor Certificate check works (native CertificateManager)
aspire run (TestShop.AppHost) Full E2E: cert check, build, connect, dashboard
aspire-managed dashboard Dashboard starts and serves
aspire-managed server AppHost server starts
aspire-managed nuget search Returns packages from nuget.org
Build with TreatWarningsAsErrors 0 warnings, 0 errors

What is next

  • Cross-platform testing (Linux, macOS)
  • Size optimization (trimming aspire-managed)
  • Multi-platform build workflow

@github-actions
Copy link
Contributor

github-actions bot commented Feb 11, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14441

Or

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

@github-actions
Copy link
Contributor

github-actions bot commented Feb 11, 2026

🎬 CLI E2E Test Recordings

The following terminal recordings are available for commit fd86da3:

Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AgentInitCommand_WithMalformedMcpJson_ShowsErrorAndExitsNonZero ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
CreateAndDeployToDockerCompose ▶️ View Recording
CreateAndDeployToDockerComposeInteractive ▶️ View Recording
CreateAndPublishToKubernetes ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateEmptyAppHostProject ▶️ View Recording
CreateStartAndStopAspireProject ▶️ View Recording
CreateStartWaitAndStopAspireProject ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopAllAppHostsFromUnrelatedDirectory ▶️ View Recording
StopNonInteractiveMultipleAppHostsShowsError ❌ Upload failed
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording

📹 Recordings uploaded automatically from CI run #22343598518

@davidfowl davidfowl force-pushed the davidfowl/aspire-managed branch from 61b8f76 to 4ca1a0a Compare February 11, 2026 15:54
@davidfowl davidfowl changed the title POC: aspire-managed unified bootstrapper aspire-managed unified binary + native certificate management Feb 11, 2026

namespace Microsoft.AspNetCore.Certificates.Generation;

internal abstract class CertificateManager
Copy link
Member

Choose a reason for hiding this comment

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

Uggh do we really want to dupe all this code?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it's not ideal. The alternatives are:

  1. Keep spawning dotnet dev-certs - requires SDK on the machine, adds ~2s startup latency per check, and the subprocess approach is fragile
  2. Reference aspnetcore's shared source via submodule/source package - they don't ship this as a package, it's internal shared source
  3. Vendor it (current approach) - one-time copy, ~2,700 lines, stable code that rarely changes

The vendored code is the same approach aspnetcore uses internally (they share it across projects via shared source). The code is very stable - last meaningful change was the V6 cert version bump. Happy to discuss alternatives if you have ideas.

Copy link
Member Author

Choose a reason for hiding this comment

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

We have plans to replace this with our own implementation as soon as @danegsta and @DamianEdwards are ready.

Copy link
Member

Choose a reason for hiding this comment

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

I planned on going the vendor approach as the basis of our implementation for the same reasons you outlined. I figure we go with a few implementation details that'll make it easier for us to keep up-to-date with the upstream code to take any fixes:

First we'll make minimal changes to CertificateManager to support generating with our assigned OID and to create a CA capable root certificate, all Aspire specific extensions of the base logic (generating intermediate certificate, leaf certificate, etc.) will go into a derived class. For the OS specific implementations we'll make them partial classes so that we can similarly separate the common logic we'll share with ASP.NET Core from our specific features.

We won't ever be able to naively copy and paste upstream changes, but we can minimize the pain as much as possible.

Copy link
Member

Choose a reason for hiding this comment

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

The main source of drift from CertificateManager in our current plan is that we'll implement a full CA chain (root, intermediate, leaf certificates) vs. the ASP.NET Core model of a single self-signed root. There's an approved reference design we have to start with, but I don't doubt that we'll need to get approval for some tweaks to make things make sense for Aspire as the approved reference design is very aggressive for how long certificates are valid which will be a pain to integrate with persistent containers.

Copy link
Member Author

Choose a reason for hiding this comment

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

@davidfowl davidfowl force-pushed the davidfowl/aspire-managed branch from a33d43c to 59f1a12 Compare February 24, 2026 00:24
@davidfowl davidfowl changed the base branch from main to release/13.2 February 24, 2026 00:24
@davidfowl davidfowl marked this pull request as ready for review February 24, 2026 00:37
Copilot AI review requested due to automatic review settings February 24, 2026 00:37
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR consolidates Aspire’s bundled managed components into a single self-contained executable (aspire-managed) and moves HTTPS dev-certificate management into the native AOT CLI via a vendored CertificateManager, simplifying bundle layout and reducing external tool/runtime dependencies.

Changes:

  • Introduces src/Aspire.Managed unified dispatcher binary (dashboard|server|nuget) and updates bundle creation/layout to ship managed/aspire-managed + dcp/ only.
  • Ports ASP.NET Core dev-certs logic into the CLI (native CertificateManager) and removes the prior bundle/SDK subprocess runners.
  • Updates bundle discovery/layout APIs, scripts, and docs to align with the new layout and execution model.

Reviewed changes

Copilot reviewed 42 out of 42 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tools/CreateLayout/README.md Updates CreateLayout prerequisites to publish Aspire.Managed instead of multiple managed outputs.
tools/CreateLayout/Program.cs Simplifies layout build: copy aspire-managed + wwwroot, removes runtime download/extraction logic.
tests/Aspire.Hosting.Tests/Dashboard/DashboardResourceTests.cs Removes outdated comments; minor assertion comment cleanup.
tests/Aspire.Hosting.Tests/Dashboard/DashboardLifecycleHookTests.cs Removes outdated comments and clarifies assertions.
src/Shared/BundleDiscovery.cs Replaces runtime/dashboard/server discovery constants with managed/aspire-managed discovery helpers.
src/Aspire.Managed/Program.cs Adds unified entry point dispatching to Dashboard, RemoteHost server, and NuGet commands.
src/Aspire.Managed/NuGet/NuGetLogger.cs Moves NuGet logger to Aspire.Managed namespace.
src/Aspire.Managed/NuGet/Commands/SearchCommand.cs Renames namespace for managed NuGet search command.
src/Aspire.Managed/NuGet/Commands/RestoreCommand.cs Renames namespace for managed NuGet restore command.
src/Aspire.Managed/NuGet/Commands/LayoutCommand.cs Renames namespace for managed NuGet layout command.
src/Aspire.Managed/Aspire.Managed.csproj New self-contained single-file publish project referencing Dashboard + RemoteHost + NuGet packages.
src/Aspire.Hosting/Dashboard/DashboardEventHandlers.cs Launches dashboard via aspire-managed dashboard when detected; otherwise uses dotnet exec.
src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs Runs server via aspire-managed server and wires dashboard env var to managed path.
src/Aspire.Cli/Projects/AppHostServerProject.cs Uses layout.GetManagedPath() for prebuilt server selection.
src/Aspire.Cli/Program.cs Registers native CertificateManager + NativeCertificateToolRunner via DI.
src/Aspire.Cli/NuGet/BundleNuGetService.cs Runs NuGet operations via aspire-managed nuget ... instead of separate helper tool.
src/Aspire.Cli/NuGet/BundleNuGetPackageCache.cs Runs NuGet search via aspire-managed nuget search.
src/Aspire.Cli/Layout/LayoutProcessRunner.cs Simplifies process runner: tools always run as executables (no muxer/DOTNET_ROOT).
src/Aspire.Cli/Layout/LayoutDiscovery.cs Updates bundle layout inference/validation to require managed/ + dcp/.
src/Aspire.Cli/Layout/LayoutConfiguration.cs Replaces runtime/dashboard/server/nuget/dev-certs components with single Managed component.
src/Aspire.Cli/Certificates/SdkCertificateToolRunner.cs Removes SDK subprocess runner implementation.
src/Aspire.Cli/Certificates/NativeCertificateToolRunner.cs New native certificate runner calling CertificateManager directly.
src/Aspire.Cli/Certificates/CertificateGeneration/CertificateManager.cs Vendored CertificateManager core with ILogger-based logging and platform selection.
src/Aspire.Cli/Certificates/CertificateGeneration/WindowsCertificateManager.cs Vendored Windows cert manager implementation.
src/Aspire.Cli/Certificates/CertificateGeneration/UnixCertificateManager.cs Vendored Unix cert manager implementation (OpenSSL/NSS/WSL handling).
src/Aspire.Cli/Certificates/CertificateGeneration/MacOSCertificateManager.cs Vendored macOS cert manager implementation (security tool/keychain).
src/Aspire.Cli/Certificates/CertificateGeneration/EnsureCertificateResult.cs Vendored ensure-cert result enum.
src/Aspire.Cli/Certificates/CertificateGeneration/ImportCertificateResult.cs Vendored import-cert result enum.
src/Aspire.Cli/Certificates/CertificateGeneration/CertificatePurpose.cs Vendored certificate purpose enum.
src/Aspire.Cli/Certificates/CertificateGeneration/CertificateExportFormat.cs Vendored export format enum.
src/Aspire.Cli/Certificates/BundleCertificateToolRunner.cs Removes bundle dev-certs subprocess runner.
src/Aspire.Cli/Bundles/BundleService.cs Updates bundle extraction cleanup directories to managed/ + dcp/.
src/Aspire.Cli.NuGetHelper/Program.cs Removes standalone NuGet helper tool entry point.
src/Aspire.Cli.NuGetHelper/Aspire.Cli.NuGetHelper.csproj Removes standalone NuGet helper tool project.
localhive.sh Adds bundle install flow (managed + dcp) and optional native AOT build option.
localhive.ps1 Adds bundle install flow (managed + dcp) and optional native AOT build option.
eng/build.sh Stops forwarding bundle runtime version into Bundle.proj.
eng/build.ps1 Stops forwarding bundle runtime version into Bundle.proj.
eng/Versions.props Removes BundleRuntimeVersion.
eng/Bundle.proj Publishes Aspire.Managed self-contained for RID; updates CreateLayout invocation args accordingly.
docs/specs/bundle.md Updates bundle spec to new layout (managed binary, native cert management) and env var guidance.
Aspire.slnx Removes NuGet helper project from solution.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl davidfowl force-pushed the davidfowl/aspire-managed branch from ac46667 to 89269bf Compare February 24, 2026 08:16
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mitchdenny
Copy link
Member

/deployment-test

@github-actions
Copy link
Contributor

🚀 Deployment tests starting on PR #14441...

This will deploy to real Azure infrastructure. Results will be posted here when complete.

View workflow run

@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions github-actions bot temporarily deployed to deployment-testing February 24, 2026 10:03 Inactive
@github-actions
Copy link
Contributor

Deployment E2E Tests passed

Summary: 23 passed, 0 failed, 0 cancelled

View workflow run

Passed Tests

  • ✅ AcaCompactNamingDeploymentTests
  • ✅ AcaCustomRegistryDeploymentTests
  • ✅ AzureAppConfigDeploymentTests
  • ✅ AcaCompactNamingUpgradeDeploymentTests
  • ✅ AksStarterWithRedisDeploymentTests
  • ✅ AksStarterDeploymentTests
  • ✅ AppServicePythonDeploymentTests
  • ✅ AcaStarterDeploymentTests
  • ✅ AzureContainerRegistryDeploymentTests
  • ✅ AcaExistingRegistryDeploymentTests
  • ✅ AuthenticationTests
  • ✅ VnetSqlServerInfraDeploymentTests
  • ✅ AppServiceReactDeploymentTests
  • ✅ AzureServiceBusDeploymentTests
  • ✅ VnetKeyVaultConnectivityDeploymentTests
  • ✅ VnetKeyVaultInfraDeploymentTests
  • ✅ AzureStorageDeploymentTests
  • ✅ AzureEventHubsDeploymentTests
  • ✅ PythonFastApiDeploymentTests
  • ✅ AzureLogAnalyticsDeploymentTests
  • ✅ VnetStorageBlobConnectivityDeploymentTests
  • ✅ VnetStorageBlobInfraDeploymentTests
  • ✅ AzureKeyVaultDeploymentTests

🎬 Terminal Recordings

Test Recording
DeployAzureAppConfigResource ▶️ View Recording
DeployAzureContainerRegistryResource ▶️ View Recording
DeployAzureEventHubsResource ▶️ View Recording
DeployAzureKeyVaultResource ▶️ View Recording
DeployAzureLogAnalyticsResource ▶️ View Recording
DeployAzureServiceBusResource ▶️ View Recording
DeployAzureStorageResource ▶️ View Recording
DeployPythonFastApiTemplateToAzureAppService ▶️ View Recording
DeployPythonFastApiTemplateToAzureContainerApps ▶️ View Recording
DeployReactTemplateToAzureAppService ▶️ View Recording
DeployStarterTemplateToAks ▶️ View Recording
DeployStarterTemplateToAzureContainerApps ▶️ View Recording
DeployStarterTemplateWithCustomRegistry ▶️ View Recording
DeployStarterTemplateWithExistingRegistry ▶️ View Recording
DeployStarterTemplateWithKeyVaultPrivateEndpoint ▶️ View Recording
DeployStarterTemplateWithRedisToAks ▶️ View Recording
DeployStarterTemplateWithStorageBlobPrivateEndpoint ▶️ View Recording
DeployVnetKeyVaultInfrastructure ▶️ View Recording
DeployVnetSqlServerInfrastructure ▶️ View Recording
DeployVnetStorageBlobInfrastructure ▶️ View Recording
DeployWithCompactNamingFixesStorageCollision ▶️ View Recording
UpgradeFromGaToDevDoesNotDuplicateStorageAccounts ▶️ View Recording

Copy link
Member

@mitchdenny mitchdenny left a comment

Choose a reason for hiding this comment

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

Did manual verification locally on Linux including removing .NET from path and doing init. and launching. Works well.

@mitchdenny mitchdenny merged commit 3d9f4e7 into release/13.2 Feb 24, 2026
371 checks passed
@mitchdenny mitchdenny deleted the davidfowl/aspire-managed branch February 24, 2026 10:52
@mitchdenny
Copy link
Member

... also ran deployment test suite to make sure that code path didn't break.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants