Skip to content

Enable NuGet signature verification for aspire-managed on Linux#16049

Merged
eerhardt merged 6 commits into
microsoft:mainfrom
eerhardt:NuGetValidationRedux
Apr 14, 2026
Merged

Enable NuGet signature verification for aspire-managed on Linux#16049
eerhardt merged 6 commits into
microsoft:mainfrom
eerhardt:NuGetValidationRedux

Conversation

@eerhardt
Copy link
Copy Markdown
Member

Description

Enable NuGet package signature verification for aspire-managed on Linux, matching the .NET SDK's behavior.

Currently, aspire restore does not verify NuGet package signatures because:

  1. The DOTNET_NUGET_SIGNATURE_VERIFICATION environment variable is not set when spawning aspire-managed processes
  2. The trusted root certificates from the .NET SDK are not available to the NuGet code running inside aspire-managed

This PR fixes both issues:

  • NuGetSignatureVerificationEnabler (in Aspire.Cli): Sets DOTNET_NUGET_SIGNATURE_VERIFICATION=true on Linux when spawning aspire-managed processes, mirroring the .NET SDK's NuGetSignatureVerificationEnabler. Respects user override to false.

  • Embedded PEM certificates (in Aspire.Managed.csproj): Embeds the SDK's codesignctl.pem and timestampctl.pem trusted root certificates as assembly resources.

  • TrustedRootsHelper (in Aspire.Managed): Extracts embedded PEM resources and uses reflection to initialize NuGet's X509TrustStore with the proper certificate chain factories. Reflection is needed because aspire-managed is a single-file app where NuGet's fallback certificate bundle discovery (assembly-relative path) doesn't work since Assembly.Location returns empty string. (We need Aot compatible: NuGet.Packaging NuGet/NuGet.Client#7197 in order to not use reflection. Will update when that is released.)

Porting #15294 to main after it wasn't taken in release/13.2.

Fixes #15282

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
  • Did you add public API?
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?
    • No

@eerhardt eerhardt requested a review from davidfowl April 10, 2026 22:06
Copilot AI review requested due to automatic review settings April 10, 2026 22:06
@eerhardt
Copy link
Copy Markdown
Member Author

/deployment-test

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 10, 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/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16049

Or

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

Copy link
Copy Markdown
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 enables NuGet package signature verification for aspire-managed on Linux to align aspire restore behavior with the .NET SDK by ensuring the verification env var is set for spawned processes and providing trusted root certificates to NuGet inside the single-file aspire-managed host.

Changes:

  • Add a CLI-side enabler to default DOTNET_NUGET_SIGNATURE_VERIFICATION=true on Linux for spawned aspire-managed processes (with a feature flag + user override to false).
  • Embed the .NET SDK’s trusted root PEM certificates into aspire-managed and initialize NuGet’s trust store via reflection/DispatchProxy at restore time.
  • Adjust tests (bundle selection behavior in deployment E2E; update unit tests for the BundleNuGetService constructor change).

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/Aspire.Deployment.EndToEnd.Tests/TypeScriptExpressDeploymentTests.cs Adjusts CI version-selection flow to pick PR build when running under a PR.
tests/Aspire.Cli.Tests/Projects/PrebuiltAppHostServerTests.cs Updates test construction to match new BundleNuGetService constructor signature.
src/Aspire.Managed/NuGet/TrustedRootsHelper.cs Adds Linux-only trust store initialization from embedded PEM resources using reflection/DispatchProxy.
src/Aspire.Managed/NuGet/Commands/RestoreCommand.cs Invokes trust store initialization before running NuGet restore.
src/Aspire.Managed/Aspire.Managed.csproj Embeds SDK trustedroots *.pem files as assembly resources with stable logical names.
src/Aspire.Cli/NuGet/NuGetSignatureVerificationEnabler.cs Adds feature-flagged env-var defaulting for spawned aspire-managed processes on Linux.
src/Aspire.Cli/NuGet/BundleNuGetService.cs Plumbs feature flags into aspire-managed process env vars for restore/layout invocations.
src/Aspire.Cli/KnownFeatures.cs Registers the new nugetSignatureVerificationEnabled feature flag (default: true).

Comment thread src/Aspire.Cli/NuGet/NuGetSignatureVerificationEnabler.cs Outdated
Comment thread src/Aspire.Managed/NuGet/TrustedRootsHelper.cs Outdated
@davidfowl
Copy link
Copy Markdown
Contributor

Logs shouldn't be using string interpolation. There's are overloads for Log{level} that take an exception as the first argument and a message.

@eerhardt
Copy link
Copy Markdown
Member Author

/deployment-test

@github-actions
Copy link
Copy Markdown
Contributor

🚀 Deployment tests starting on PR #16049...

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 April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot had a problem deploying to deployment-testing April 11, 2026 01:31 Failure
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot had a problem deploying to deployment-testing April 11, 2026 01:31 Failure
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
@github-actions github-actions Bot had a problem deploying to deployment-testing April 11, 2026 01:31 Failure
@github-actions github-actions Bot had a problem deploying to deployment-testing April 11, 2026 01:31 Failure
@github-actions github-actions Bot temporarily deployed to deployment-testing April 11, 2026 01:31 Inactive
Comment thread src/Aspire.Managed/NuGet/TrustedRootsHelper.cs
Comment thread src/Aspire.Managed/NuGet/TrustedRootsHelper.cs Outdated
Copy link
Copy Markdown
Member

@JamesNK JamesNK left a comment

Choose a reason for hiding this comment

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

2 comments on TrustedRootsHelper robustness (1 medium, 1 low).

Comment thread src/Aspire.Managed/NuGet/TrustedRootsHelper.cs
Comment thread src/Aspire.Managed/NuGet/TrustedRootsHelper.cs
Comment thread src/Aspire.Managed/NuGet/TrustedRootsHelper.cs Outdated
Comment on lines +68 to +69
var chainFactoryInterfaceType = nugetPackagingAssembly.GetType("NuGet.Packaging.Signing.IX509ChainFactory");
var chainInterfaceType = nugetPackagingAssembly.GetType("NuGet.Packaging.Signing.IX509Chain");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

😬

Have we talked with NuGet team about making these public?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We need NuGet/NuGet.Client#7197 in order to not use reflection. It hasn't been released yet.

When it is, we can write the files to a folder next to us, and won't need this reflection.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there an issue to track fixing the reflection?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Set DOTNET_NUGET_SIGNATURE_VERIFICATION=true when spawning aspire-managed
processes on Linux, mirroring the .NET SDK's NuGetSignatureVerificationEnabler
behavior. Embed the SDK's trusted root PEM certificates (codesignctl.pem,
timestampctl.pem) as resources in Aspire.Managed, and initialize NuGet's
X509TrustStore via reflection before running restore operations. This is
needed because aspire-managed is a single-file app where NuGet's fallback
certificate bundle discovery (assembly-relative path) doesn't work.

Fixes microsoft#15282

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eerhardt eerhardt force-pushed the NuGetValidationRedux branch from dd13e4c to 3a02a0d Compare April 13, 2026 17:48
@eerhardt
Copy link
Copy Markdown
Member Author

/deployment-test

@github-actions
Copy link
Copy Markdown
Contributor

🚀 Deployment tests starting on PR #16049...

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 April 13, 2026 18:30 Inactive
@github-actions github-actions Bot had a problem deploying to deployment-testing April 13, 2026 18:30 Failure
@github-actions github-actions Bot temporarily deployed to deployment-testing April 13, 2026 18:30 Inactive
@github-actions github-actions Bot temporarily deployed to deployment-testing April 13, 2026 18:30 Inactive
@joperezr
Copy link
Copy Markdown
Member

closing and reopening to try to trigger the checks.

@github-actions
Copy link
Copy Markdown
Contributor

Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

@eerhardt
Copy link
Copy Markdown
Member Author

/deployment-test

@github-actions
Copy link
Copy Markdown
Contributor

🚀 Deployment tests starting on PR #16049...

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

View workflow run

@eerhardt
Copy link
Copy Markdown
Member Author

/deployment-test

@github-actions
Copy link
Copy Markdown
Contributor

🚀 Deployment tests starting on PR #16049...

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

View workflow run

Python templates now use TypeScript AppHost (apphost.ts) not C# single-file
AppHost (apphost.cs). Updated PythonFastApi, AppServicePython, and AcrPurgeTask
tests to modify apphost.ts with the correct TypeScript API calls.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eerhardt
Copy link
Copy Markdown
Member Author

/deployment-test

@github-actions
Copy link
Copy Markdown
Contributor

🚀 Deployment tests starting on PR #16049...

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

View workflow run

@github-actions
Copy link
Copy Markdown
Contributor

Deployment E2E Tests failed — 26 passed, 4 failed, 0 cancelled

View test results and recordings

View workflow run

Test Result Recording
Deployment.EndToEnd-AcaCompactNamingDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-VnetKeyVaultInfraDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-VnetSqlServerInfraDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AzureStorageDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-VnetSqlServerConnectivityDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-NspStorageKeyVaultDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-TypeScriptExpressDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-TypeScriptVnetSqlServerInfraDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-VnetKeyVaultConnectivityDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AzureServiceBusDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AzureContainerRegistryDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AppServiceReactDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AzureLogAnalyticsDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AzureAppConfigDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AuthenticationTests ✅ Passed
Deployment.EndToEnd-AzureEventHubsDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AksStarterWithRedisDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AzureKeyVaultDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AcaStarterDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-VnetStorageBlobConnectivityDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AcaDeploymentErrorOutputTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AcaManagedRedisDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AcaCustomRegistryDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AksStarterDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-VnetStorageBlobInfraDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-AcaExistingRegistryDeploymentTests ✅ Passed ▶️ View Recording
Deployment.EndToEnd-PythonFastApiDeploymentTests ❌ Failed ▶️ View Recording
Deployment.EndToEnd-AppServicePythonDeploymentTests ❌ Failed ▶️ View Recording
Deployment.EndToEnd-AcrPurgeTaskDeploymentTests ❌ Failed ▶️ View Recording
Deployment.EndToEnd-AcaCompactNamingUpgradeDeploymentTests ❌ Failed ▶️ View Recording

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Aspire polyglot should enable nuget signature verification on Linux

5 participants