| File: NuGet\NuGetSignatureVerificationEnabler.cs | Web Access |
| Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Cli.Configuration; namespace Aspire.Cli.NuGet; /// <summary> /// Enables NuGet signature verification for NuGet operations. /// Mirrors the .NET SDK's NuGetSignatureVerificationEnabler behavior. /// </summary> internal static class NuGetSignatureVerificationEnabler { internal const string DotNetNuGetSignatureVerification = "DOTNET_NUGET_SIGNATURE_VERIFICATION"; private static readonly Lock s_currentProcessLock = new(); private static int s_currentProcessScopeCount; private static string? s_previousCurrentProcessValue; /// <summary> /// Applies NuGet signature verification environment variables to the given dictionary. /// On Linux, sets DOTNET_NUGET_SIGNATURE_VERIFICATION to "true" unless the user /// has explicitly set it to "false". The behavior can be disabled via the /// <see cref="KnownFeatures.NuGetSignatureVerificationEnabled"/> feature flag. /// </summary> public static void Apply(Dictionary<string, string> environmentVariables, IFeatures features, IEnvironment environment) { if (!environment.IsLinux() || !features.IsFeatureEnabled( KnownFeatures.NuGetSignatureVerificationEnabled, KnownFeatures.GetFeatureMetadata(KnownFeatures.NuGetSignatureVerificationEnabled)!.DefaultValue)) { return; } var value = environment.GetEnvironmentVariable(DotNetNuGetSignatureVerification); // If the user explicitly set it to "false", respect that var effectiveValue = bool.TryParse(value, out var boolValue) && !boolValue ? bool.FalseString : bool.TrueString; environmentVariables[DotNetNuGetSignatureVerification] = effectiveValue; } /// <summary> /// Applies NuGet signature verification to the current process until the returned scope is disposed. /// </summary> /// <remarks> /// The aspire-managed helper received this variable only in its own environment. The in-process client needs it /// in the CLI's environment because NuGet reads it from there, so it is set for the duration of each operation and /// the previous value is restored when the last overlapping scope ends. Otherwise it would leak into every process /// the CLI starts afterwards. /// </remarks> public static IDisposable ApplyToCurrentProcess(IFeatures features, IEnvironment environment) { lock (s_currentProcessLock) { if (s_currentProcessScopeCount++ == 0) { s_previousCurrentProcessValue = Environment.GetEnvironmentVariable(DotNetNuGetSignatureVerification); var environmentVariables = new Dictionary<string, string>(); Apply(environmentVariables, features, environment); if (environmentVariables.TryGetValue(DotNetNuGetSignatureVerification, out var value)) { Environment.SetEnvironmentVariable(DotNetNuGetSignatureVerification, value); } } } return new CurrentProcessScope(); } private sealed class CurrentProcessScope : IDisposable { private int _disposed; public void Dispose() { if (Interlocked.Exchange(ref _disposed, 1) != 0) { return; } lock (s_currentProcessLock) { if (--s_currentProcessScopeCount == 0) { Environment.SetEnvironmentVariable(DotNetNuGetSignatureVerification, s_previousCurrentProcessValue); s_previousCurrentProcessValue = null; } } } } }