Skip to content

Commit 3eafa1f

Browse files
authored
Signing: enable NuGet signature verification by default on Linux (#31868)
Resolve NuGet/Home#11262
1 parent d9858bc commit 3eafa1f

File tree

5 files changed

+236
-0
lines changed

5 files changed

+236
-0
lines changed

src/Cli/dotnet/NuGetForwardingApp.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ public NuGetForwardingApp(IEnumerable<string> argsToForward)
1919
_forwardingApp = new ForwardingApp(
2020
GetNuGetExePath(),
2121
argsToForward);
22+
23+
NuGetSignatureVerificationEnabler.ConditionallyEnable(_forwardingApp);
2224
}
2325

2426
public int Execute()
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
#nullable enable
5+
6+
using System;
7+
using System.Runtime.InteropServices;
8+
using Microsoft.DotNet.Cli;
9+
using Microsoft.DotNet.Cli.Utils;
10+
using Microsoft.DotNet.Tools.MSBuild;
11+
12+
namespace Microsoft.DotNet.Tools
13+
{
14+
public static class NuGetSignatureVerificationEnabler
15+
{
16+
private static readonly EnvironmentProvider s_environmentProvider = new();
17+
18+
internal static readonly string DotNetNuGetSignatureVerification = "DOTNET_NUGET_SIGNATURE_VERIFICATION";
19+
20+
public static void ConditionallyEnable(ForwardingApp forwardingApp, IEnvironmentProvider? environmentProvider = null)
21+
{
22+
ArgumentNullException.ThrowIfNull(forwardingApp, nameof(forwardingApp));
23+
24+
if (!IsLinux())
25+
{
26+
return;
27+
}
28+
29+
string value = GetSignatureVerificationEnablementValue(environmentProvider);
30+
31+
forwardingApp.WithEnvironmentVariable(DotNetNuGetSignatureVerification, value);
32+
}
33+
34+
public static void ConditionallyEnable(MSBuildForwardingApp forwardingApp, IEnvironmentProvider? environmentProvider = null)
35+
{
36+
ArgumentNullException.ThrowIfNull(forwardingApp, nameof(forwardingApp));
37+
38+
if (!IsLinux())
39+
{
40+
return;
41+
}
42+
43+
string value = GetSignatureVerificationEnablementValue(environmentProvider);
44+
45+
forwardingApp.EnvironmentVariable(DotNetNuGetSignatureVerification, value);
46+
}
47+
48+
private static string GetSignatureVerificationEnablementValue(IEnvironmentProvider? environmentProvider)
49+
{
50+
string? value = (environmentProvider ?? s_environmentProvider).GetEnvironmentVariable(DotNetNuGetSignatureVerification);
51+
52+
return string.Equals(bool.FalseString, value, StringComparison.OrdinalIgnoreCase)
53+
? bool.FalseString : bool.TrueString;
54+
}
55+
56+
private static bool IsLinux()
57+
{
58+
return RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
59+
}
60+
}
61+
}

src/Cli/dotnet/commands/RestoringCommand.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public RestoringCommand(
3030
Task.Run(() => WorkloadManifestUpdater.BackgroundUpdateAdvertisingManifestsAsync(userProfileDir));
3131
SeparateRestoreCommand = GetSeparateRestoreCommand(msbuildArgs, noRestore, msbuildPath);
3232
AdvertiseWorkloadUpdates = advertiseWorkloadUpdates;
33+
34+
if (!noRestore)
35+
{
36+
NuGetSignatureVerificationEnabler.ConditionallyEnable(this);
37+
}
3338
}
3439

3540
private static IEnumerable<string> GetCommandArguments(

src/Cli/dotnet/commands/dotnet-restore/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class RestoreCommand : MSBuildForwardingApp
1717
public RestoreCommand(IEnumerable<string> msbuildArgs, string msbuildPath = null)
1818
: base(msbuildArgs, msbuildPath)
1919
{
20+
NuGetSignatureVerificationEnabler.ConditionallyEnable(this);
2021
}
2122

2223
public static RestoreCommand FromArgs(string[] args, string msbuildPath = null, bool noLogo = true)
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
#nullable enable
5+
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Diagnostics;
9+
using System.IO;
10+
using Xunit;
11+
using Microsoft.DotNet.Cli;
12+
using Microsoft.DotNet.Cli.Utils;
13+
using Microsoft.DotNet.Tools;
14+
using Microsoft.DotNet.Tools.MSBuild;
15+
using Moq;
16+
17+
namespace Microsoft.DotNet.Tests
18+
{
19+
public class NuGetSignatureVerificationEnablerTests
20+
{
21+
private static readonly string FakeFilePath = Path.Combine(Path.GetTempPath(), "file.fake");
22+
23+
public static IEnumerable<object[]> GetNonFalseValues()
24+
{
25+
yield return new object[] { null! };
26+
yield return new object[] { string.Empty };
27+
yield return new object[] { "0" };
28+
yield return new object[] { "1" };
29+
yield return new object[] { "no" };
30+
yield return new object[] { "yes" };
31+
yield return new object[] { "true" };
32+
yield return new object[] { "TRUE" };
33+
}
34+
35+
public static IEnumerable<object[]> GetFalseValues()
36+
{
37+
yield return new object[] { "false" };
38+
yield return new object[] { "FALSE" };
39+
}
40+
41+
[Fact]
42+
public void GivenANullForwardingAppThrows()
43+
{
44+
ForwardingApp forwardingApp = null!;
45+
46+
ArgumentNullException exception = Assert.Throws<ArgumentNullException>(
47+
() => NuGetSignatureVerificationEnabler.ConditionallyEnable(forwardingApp));
48+
49+
Assert.Equal("forwardingApp", exception.ParamName);
50+
}
51+
52+
[Fact]
53+
public void GivenANullMSBuildForwardingAppThrows()
54+
{
55+
MSBuildForwardingApp forwardingApp = null!;
56+
57+
ArgumentNullException exception = Assert.Throws<ArgumentNullException>(
58+
() => NuGetSignatureVerificationEnabler.ConditionallyEnable(forwardingApp));
59+
60+
Assert.Equal("forwardingApp", exception.ParamName);
61+
}
62+
63+
[LinuxOnlyTheory]
64+
[MemberData(nameof(GetNonFalseValues))]
65+
public void GivenAForwardingAppAndAnEnvironmentVariableValueThatIsNotFalseSetsTrueOnLinux(string? value)
66+
{
67+
Mock<IEnvironmentProvider> environmentProvider = CreateEnvironmentProvider(value);
68+
ForwardingApp forwardingApp = new(FakeFilePath, Array.Empty<string>());
69+
70+
NuGetSignatureVerificationEnabler.ConditionallyEnable(forwardingApp, environmentProvider.Object);
71+
72+
environmentProvider.VerifyAll();
73+
74+
VerifyEnvironmentVariable(forwardingApp.GetProcessStartInfo(), bool.TrueString);
75+
}
76+
77+
[LinuxOnlyTheory]
78+
[MemberData(nameof(GetFalseValues))]
79+
public void GivenAForwardingAppAndAnEnvironmentVariableValueThatIsFalseSetsFalseOnLinux(string value)
80+
{
81+
Mock<IEnvironmentProvider> environmentProvider = CreateEnvironmentProvider(value);
82+
ForwardingApp forwardingApp = new(FakeFilePath, Array.Empty<string>());
83+
84+
NuGetSignatureVerificationEnabler.ConditionallyEnable(forwardingApp, environmentProvider.Object);
85+
86+
environmentProvider.VerifyAll();
87+
88+
VerifyEnvironmentVariable(forwardingApp.GetProcessStartInfo(), bool.FalseString);
89+
}
90+
91+
[LinuxOnlyTheory]
92+
[MemberData(nameof(GetNonFalseValues))]
93+
public void GivenAnMSBuildForwardingAppAndAnEnvironmentVariableValueThatIsNotFalseSetsTrueOnLinux(string? value)
94+
{
95+
Mock<IEnvironmentProvider> environmentProvider = CreateEnvironmentProvider(value);
96+
MSBuildForwardingApp forwardingApp = new(Array.Empty<string>(), FakeFilePath);
97+
98+
NuGetSignatureVerificationEnabler.ConditionallyEnable(forwardingApp, environmentProvider.Object);
99+
100+
environmentProvider.VerifyAll();
101+
102+
VerifyEnvironmentVariable(forwardingApp.GetProcessStartInfo(), bool.TrueString);
103+
}
104+
105+
[LinuxOnlyTheory]
106+
[MemberData(nameof(GetFalseValues))]
107+
public void GivenAnMSBuildForwardingAppAndAnEnvironmentVariableValueThatIsFalseSetsFalseOnLinux(string value)
108+
{
109+
Mock<IEnvironmentProvider> environmentProvider = CreateEnvironmentProvider(value);
110+
MSBuildForwardingApp forwardingApp = new(Array.Empty<string>(), FakeFilePath);
111+
112+
NuGetSignatureVerificationEnabler.ConditionallyEnable(forwardingApp, environmentProvider.Object);
113+
114+
environmentProvider.VerifyAll();
115+
116+
VerifyEnvironmentVariable(forwardingApp.GetProcessStartInfo(), bool.FalseString);
117+
}
118+
119+
[MacOSOnlyFact]
120+
public void GivenAForwardingAppDoesNothingOnMacOs()
121+
{
122+
var environmentProvider = new Mock<IEnvironmentProvider>(MockBehavior.Strict);
123+
ForwardingApp forwardingApp = new(FakeFilePath, Array.Empty<string>());
124+
125+
NuGetSignatureVerificationEnabler.ConditionallyEnable(forwardingApp, environmentProvider.Object);
126+
127+
environmentProvider.VerifyAll();
128+
129+
VerifyNoEnvironmentVariable(forwardingApp.GetProcessStartInfo());
130+
}
131+
132+
[MacOSOnlyFact]
133+
public void GivenAnMSBuildForwardingAppDoesNothingOnMacOs()
134+
{
135+
var environmentProvider = new Mock<IEnvironmentProvider>(MockBehavior.Strict);
136+
MSBuildForwardingApp forwardingApp = new(Array.Empty<string>(), FakeFilePath);
137+
138+
NuGetSignatureVerificationEnabler.ConditionallyEnable(forwardingApp, environmentProvider.Object);
139+
140+
environmentProvider.VerifyAll();
141+
142+
VerifyNoEnvironmentVariable(forwardingApp.GetProcessStartInfo());
143+
}
144+
145+
private static Mock<IEnvironmentProvider> CreateEnvironmentProvider(string? value)
146+
{
147+
Mock<IEnvironmentProvider> provider = new(MockBehavior.Strict);
148+
149+
provider
150+
.Setup(p => p.GetEnvironmentVariable(NuGetSignatureVerificationEnabler.DotNetNuGetSignatureVerification))
151+
.Returns(value!);
152+
153+
return provider;
154+
}
155+
156+
private static void VerifyEnvironmentVariable(ProcessStartInfo startInfo, string expectedValue)
157+
{
158+
Assert.True(startInfo.EnvironmentVariables.ContainsKey(NuGetSignatureVerificationEnabler.DotNetNuGetSignatureVerification));
159+
Assert.Equal(expectedValue, startInfo.EnvironmentVariables[NuGetSignatureVerificationEnabler.DotNetNuGetSignatureVerification]);
160+
}
161+
162+
private static void VerifyNoEnvironmentVariable(ProcessStartInfo startInfo)
163+
{
164+
Assert.False(startInfo.EnvironmentVariables.ContainsKey(NuGetSignatureVerificationEnabler.DotNetNuGetSignatureVerification));
165+
}
166+
}
167+
}

0 commit comments

Comments
 (0)