Skip to content

Commit

Permalink
SignTool: Use .NET Core MSBuild for Non-Windows (#15045)
Browse files Browse the repository at this point in the history
  • Loading branch information
ellahathaway committed Sep 5, 2024
1 parent 5602a0a commit fd7ca2e
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 16 deletions.
3 changes: 2 additions & 1 deletion Documentation/CorePackages/Signing.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ This is a MSBuild custom task that provides batch signing and simple verificatio
| FileExtensionSignInfo | Array | This is a mapping between extension (in the format ".ext") to default sign information for those kind of files. Overriding of the default sign info is done using the other parameters. |
| CertificatesSignInfo | Array | List of certificate names that can be flagged using the `DualSigningAllowed` attribute as dual certificates. |
| **MicroBuildCorePath** | Dir Path | Path to MicroBuild.Core package directory. |
| MSBuildPath | Exe path | Path to the MSBuild.exe binary used to run the signing process on MicroBuild. |
| MSBuildPath | Exe path | Path to the MSBuild.exe binary used to run the signing process on MicroBuild for Windows. |
| DotNetPath | Exe path | Path to the dotnet executable used to run the signing process on MicroBuild for Linux and Mac. |
| SNBinaryPath | Exe path | Path to the sn.exe binary used to strong-name sign / validate signature of managed files. |
| **TempDir** | Dir path | Used to store temporary files during the process of calling MicroBuild signing. |
| LogDir | Dir path | MSBuild binary log information from the signing rounds will be stored in this directory. |
Expand Down
10 changes: 9 additions & 1 deletion src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.proj
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@
<_TestSign Condition="'$(DotNetSignType)' == 'test'">true</_TestSign>

<_DesktopMSBuildRequired>false</_DesktopMSBuildRequired>
<_DesktopMSBuildRequired Condition="'$(_DryRun)' != 'true' and '$(MSBuildRuntimeType)' == 'Core'">true</_DesktopMSBuildRequired>
<_DesktopMSBuildRequired Condition="'$(_DryRun)' != 'true' and '$(MSBuildRuntimeType)' == 'Core' and '$(OS)' == 'Windows_NT'">true</_DesktopMSBuildRequired>

<_DotNetCoreRequired>false</_DotNetCoreRequired>
<_DotNetCoreRequired Condition="'$(_DryRun)' != 'true' and '$(OS)' != 'Windows_NT'">true</_DotNetCoreRequired>
</PropertyGroup>

<Error Condition="'$(AllowEmptySignList)' != 'true' AND '@(ItemsToSign)' == ''"
Expand All @@ -69,6 +72,10 @@
<_DesktopMSBuildPath Condition="!Exists('$(_DesktopMSBuildPath)')">$(_VSInstallDir)\MSBuild\15.0\Bin\msbuild.exe</_DesktopMSBuildPath>
</PropertyGroup>

<PropertyGroup Condition="$(_DotNetCoreRequired)">
<_DotNetCorePath>$(DotNetTool)</_DotNetCorePath>
</PropertyGroup>

<Microsoft.DotNet.SignTool.SignToolTask
DryRun="$(_DryRun)"
TestSign="$(_TestSign)"
Expand All @@ -82,6 +89,7 @@
TempDir="$(ArtifactsTmpDir)"
LogDir="$(ArtifactsLogDir)"
MSBuildPath="$(_DesktopMSBuildPath)"
DotNetPath="$(_DotNetCorePath)"
SNBinaryPath="$(NuGetPackageRoot)sn\$(SNVersion)\sn.exe"
MicroBuildCorePath="$(NuGetPackageRoot)microbuild.core\$(MicroBuildCoreVersion)"
WixToolsPath="$(WixInstallPath)"
Expand Down
9 changes: 7 additions & 2 deletions src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,10 @@ private void ValidateGeneratedProject(

var task = new SignToolTask { BuildEngine = buildEngine };

// The path to MSBuild will always be null in these tests, this will force
// The path to MSBuild and DotNet will always be null in these tests, this will force
// the signing logic to call our FakeBuildEngine.BuildProjectFile with a path
// to the XML that store the content of the would be Microbuild sign request.
var signToolArgs = new SignToolArgs(_tmpDir, microBuildCorePath: "MicroBuildCorePath", testSign: true, msBuildPath: null, _tmpDir, enclosingDir: "", "", wixToolsPath: wixToolsPath, tarToolPath: s_tarToolPath);
var signToolArgs = new SignToolArgs(_tmpDir, microBuildCorePath: "MicroBuildCorePath", testSign: true, msBuildPath: null, dotnetPath: null, _tmpDir, enclosingDir: "", "", wixToolsPath: wixToolsPath, tarToolPath: s_tarToolPath);

var signTool = new FakeSignTool(signToolArgs, task.Log);
var configuration = new Configuration(signToolArgs.TempDir, itemsToSign, strongNameSignInfo, fileSignInfo, extensionsSignInfo, dualCertificates, tarToolPath: s_tarToolPath, task.Log);
Expand Down Expand Up @@ -401,6 +401,7 @@ public void EmptySigningListForTask()
DryRun = false,
TestSign = true,
MSBuildPath = CreateTestResource("msbuild.fake"),
DotNetPath = CreateTestResource("dotnet.fake"),
SNBinaryPath = CreateTestResource("fake.sn.exe")
};

Expand All @@ -420,6 +421,7 @@ public void SignWhenSnExeIsNotRequired()
DryRun = false,
TestSign = true,
MSBuildPath = CreateTestResource("msbuild.fake"),
DotNetPath = CreateTestResource("dotnet.fake"),
DoStrongNameCheck = false,
SNBinaryPath = null,
};
Expand Down Expand Up @@ -1381,6 +1383,7 @@ public void BadWixToolsetPath()
TempDir = "TempDir",
DryRun = true,
MSBuildPath = CreateTestResource("msbuild.fake"),
DotNetPath = null,
DoStrongNameCheck = false,
SNBinaryPath = null,
WixToolsPath = badPath
Expand Down Expand Up @@ -1933,6 +1936,7 @@ public void ValidateSignToolTaskParsing()
TempDir = "TempDir",
DryRun = true,
MSBuildPath = CreateTestResource("msbuild.fake"),
DotNetPath = CreateTestResource("dotnet.fake"),
MicroBuildCorePath = "MicroBuildCorePath",
DoStrongNameCheck = false,
SNBinaryPath = null,
Expand Down Expand Up @@ -1967,6 +1971,7 @@ private bool runTask(ITaskItem[] itemsToSign = null, ITaskItem[] strongNameSignI
TempDir = "TempDir",
DryRun = true,
MSBuildPath = CreateTestResource("msbuild.fake"),
DotNetPath = CreateTestResource("dotnet.fake"),
DoStrongNameCheck = false,
SNBinaryPath = null,
};
Expand Down
17 changes: 14 additions & 3 deletions src/Microsoft.DotNet.SignTool/src/RealSignTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;

namespace Microsoft.DotNet.SignTool
{
Expand All @@ -17,6 +18,7 @@ namespace Microsoft.DotNet.SignTool
internal sealed class RealSignTool : SignTool
{
private readonly string _msbuildPath;
private readonly string _dotnetPath;
private readonly string _logDir;
private readonly string _snPath;

Expand All @@ -35,23 +37,32 @@ internal RealSignTool(SignToolArgs args, TaskLoggingHelper log) : base(args, log
{
TestSign = args.TestSign;
_msbuildPath = args.MSBuildPath;
_dotnetPath = args.DotNetPath;
_snPath = args.SNBinaryPath;
_logDir = args.LogDir;
}

public override bool RunMSBuild(IBuildEngine buildEngine, string projectFilePath, string binLogPath)
{
if (_msbuildPath == null)
if (_msbuildPath == null && _dotnetPath == null)
{
return buildEngine.BuildProjectFile(projectFilePath, null, null, null);
}

Directory.CreateDirectory(_logDir);

string processFileName = _dotnetPath;
string processArguments = $@"build ""{projectFilePath}"" -bl:""{binLogPath}""";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
processFileName = _msbuildPath;
processArguments = $@"""{projectFilePath}"" /bl:""{binLogPath}""";
}

var process = Process.Start(new ProcessStartInfo()
{
FileName = _msbuildPath,
Arguments = $@"""{projectFilePath}"" /bl:""{binLogPath}""",
FileName = processFileName,
Arguments = processArguments,
UseShellExecute = false,
WorkingDirectory = TempDir,
});
Expand Down
4 changes: 3 additions & 1 deletion src/Microsoft.DotNet.SignTool/src/SignToolArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@ internal readonly struct SignToolArgs
internal string MicroBuildCorePath { get; }
internal bool TestSign { get; }
internal string MSBuildPath { get; }
internal string DotNetPath { get; }
internal string SNBinaryPath { get; }
internal string LogDir { get; }
internal string EnclosingDir { get; }
internal string WixToolsPath { get; }
internal string TarToolPath { get; }

internal SignToolArgs(string tempPath, string microBuildCorePath, bool testSign, string msBuildPath, string logDir, string enclosingDir, string snBinaryPath, string wixToolsPath, string tarToolPath)
internal SignToolArgs(string tempPath, string microBuildCorePath, bool testSign, string msBuildPath, string dotnetPath, string logDir, string enclosingDir, string snBinaryPath, string wixToolsPath, string tarToolPath)
{
TempDir = tempPath;
MicroBuildCorePath = microBuildCorePath;
TestSign = testSign;
MSBuildPath = msBuildPath;
DotNetPath = dotnetPath;
LogDir = logDir;
EnclosingDir = enclosingDir;
SNBinaryPath = snBinaryPath;
Expand Down
30 changes: 22 additions & 8 deletions src/Microsoft.DotNet.SignTool/src/SignToolTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Linq;
using System.Threading.Tasks;
using System.Resources;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

namespace Microsoft.DotNet.SignTool
Expand Down Expand Up @@ -126,10 +127,15 @@ public class SignToolTask : BuildTask
public ITaskItem[] CertificatesSignInfo { get; set; }

/// <summary>
/// Path to msbuild.exe. Required if <see cref="DryRun"/> is <c>false</c>.
/// Path to msbuild.exe. Required if <see cref="DryRun"/> is <c>false</c>, OS is <c>Windows_NT</c>, and project is using .NET Core.
/// </summary>
public string MSBuildPath { get; set; }

/// <summary>
/// Path to dotnet executable. Required if <see cref="DryRun"/> is <c>false</c> and OS is not <c>Windows_NT</c>.
/// </summary>
public string DotNetPath { get; set; }

/// <summary>
/// Path to sn.exe. Required if strong name signing files locally is needed.
/// </summary>
Expand Down Expand Up @@ -180,12 +186,6 @@ public override bool Execute()

public void ExecuteImpl()
{
if (!DryRun && typeof(object).Assembly.GetName().Name != "mscorlib" && !File.Exists(MSBuildPath))
{
Log.LogError($"MSBuild was not found at this path: '{MSBuildPath}'.");
return;
}

if (!AllowEmptySignList && ItemsToSign.Count() == 0)
{
Log.LogWarning(subcategory: null,
Expand All @@ -201,6 +201,20 @@ public void ExecuteImpl()

if (!DryRun)
{
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
if (isWindows && typeof(object).Assembly.GetName().Name != "mscorlib" && !File.Exists(MSBuildPath))
{
// For Windows, desktop msbuild is required if running on .NET Core.
Log.LogError($"MSBuild was not found at this path: '{MSBuildPath}'.");
return;
}
else if (!isWindows && !File.Exists(DotNetPath))
{
// For Mac and Linux, dotnet is required.
Log.LogError($"DotNet was not found at this path: '{DotNetPath}'.");
return;
}

if(!Path.IsPathRooted(TempDir))
{
Log.LogWarning($"TempDir ('{TempDir}' is not rooted, this can cause unexpected behavior in signtool. Please provide a fully qualified 'TempDir' path.");
Expand Down Expand Up @@ -241,7 +255,7 @@ public void ExecuteImpl()

if (Log.HasLoggedErrors) return;

var signToolArgs = new SignToolArgs(TempDir, MicroBuildCorePath, TestSign, MSBuildPath, LogDir, enclosingDir, SNBinaryPath, WixToolsPath, TarToolPath);
var signToolArgs = new SignToolArgs(TempDir, MicroBuildCorePath, TestSign, MSBuildPath, DotNetPath, LogDir, enclosingDir, SNBinaryPath, WixToolsPath, TarToolPath);
var signTool = DryRun ? new ValidationOnlySignTool(signToolArgs, Log) : (SignTool)new RealSignTool(signToolArgs, Log);

Telemetry telemetry = new Telemetry();
Expand Down

0 comments on commit fd7ca2e

Please sign in to comment.