Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GitHubSync update #749

Merged
merged 1 commit into from
Nov 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
GitHubSync update
GeertvanHorrik committed Nov 28, 2024
commit 4f8d85e8aff4d4c2ccb09d124c671f0bf1281e9b
23 changes: 4 additions & 19 deletions deployment/cake/apps-wpf-tasks.cake
Original file line number Diff line number Diff line change
@@ -155,26 +155,11 @@ public class WpfProcessor : ProcessorBase
CakeContext.DeleteFiles(filesToDelete);
}

// We know we *highly likely* need to sign, so try doing this upfront
if (!string.IsNullOrWhiteSpace(BuildContext.General.CodeSign.CertificateSubjectName))
if (BuildContext.General.CodeSign.IsAvailable ||
BuildContext.General.AzureCodeSign.IsAvailable)
{
BuildContext.CakeContext.Information("Searching for packagable files to sign:");

var projectFilesToSign = new List<FilePath>();

var exeSignFilesSearchPattern = $"{BuildContext.General.OutputRootDirectory}/{wpfApp}/**/*.exe";
BuildContext.CakeContext.Information($" - {exeSignFilesSearchPattern}");
projectFilesToSign.AddRange(BuildContext.CakeContext.GetFiles(exeSignFilesSearchPattern));

var dllSignFilesSearchPattern = $"{BuildContext.General.OutputRootDirectory}/{wpfApp}/**/*.dll";
BuildContext.CakeContext.Information($" - {dllSignFilesSearchPattern}");
projectFilesToSign.AddRange(BuildContext.CakeContext.GetFiles(dllSignFilesSearchPattern));

var signToolCommand = string.Format("sign /a /t {0} /n {1} /fd {2}", BuildContext.General.CodeSign.TimeStampUri,
BuildContext.General.CodeSign.CertificateSubjectName, BuildContext.General.CodeSign.HashAlgorithm);

SignFiles(BuildContext, signToolCommand, projectFilesToSign);
}
SignFilesInDirectory(BuildContext, outputDirectory, string.Empty);
}
else
{
BuildContext.CakeContext.Warning("No signing certificate subject name provided, not signing any files");
40 changes: 19 additions & 21 deletions deployment/cake/components-tasks.cake
Original file line number Diff line number Diff line change
@@ -314,27 +314,7 @@ public class ComponentsProcessor : ProcessorBase
BuildContext.CakeContext.LogSeparator();
}

var codeSign = (!BuildContext.General.IsCiBuild &&
!BuildContext.General.IsLocalBuild &&
!string.IsNullOrWhiteSpace(BuildContext.General.CodeSign.CertificateSubjectName));
if (codeSign)
{
// For details, see https://docs.microsoft.com/en-us/nuget/create-packages/sign-a-package
// nuget sign MyPackage.nupkg -CertificateSubjectName <MyCertSubjectName> -Timestamper <TimestampServiceURL>
var filesToSign = CakeContext.GetFiles($"{BuildContext.General.OutputRootDirectory}/*.nupkg");

foreach (var fileToSign in filesToSign)
{
CakeContext.Information($"Signing NuGet package '{fileToSign}' using certificate subject '{BuildContext.General.CodeSign.CertificateSubjectName}'");

var exitCode = CakeContext.StartProcess(BuildContext.General.NuGet.Executable, new ProcessSettings
{
Arguments = $"sign \"{fileToSign}\" -CertificateSubjectName \"{BuildContext.General.CodeSign.CertificateSubjectName}\" -Timestamper \"{BuildContext.General.CodeSign.TimeStampUri}\""
});

CakeContext.Information("Signing NuGet package exited with '{0}'", exitCode);
}
}
await SignNuGetPackageAsync();
}

public override async Task DeployAsync()
@@ -378,4 +358,22 @@ public class ComponentsProcessor : ProcessorBase
{

}

private async Task SignNuGetPackageAsync()
{
if (BuildContext.General.IsCiBuild ||
BuildContext.General.IsLocalBuild)
{
return;
}

// For details, see https://docs.microsoft.com/en-us/nuget/create-packages/sign-a-package
// nuget sign MyPackage.nupkg -CertificateSubjectName <MyCertSubjectName> -Timestamper <TimestampServiceURL>
var filesToSign = CakeContext.GetFiles($"{BuildContext.General.OutputRootDirectory}/*.nupkg");

foreach (var fileToSign in filesToSign)
{
SignNuGetPackage(BuildContext, fileToSign.FullPath);
}
}
}
6 changes: 3 additions & 3 deletions deployment/cake/generic-tasks.cake
Original file line number Diff line number Diff line change
@@ -276,10 +276,10 @@ Task("CodeSign")
return;
}

var certificateSubjectName = buildContext.General.CodeSign.CertificateSubjectName;
if (string.IsNullOrWhiteSpace(certificateSubjectName))
if (!buildContext.General.CodeSign.IsAvailable &&
!buildContext.General.AzureCodeSign.IsAvailable)
{
Information("Skipping code signing because the certificate subject name was not specified");
Information("Skipping code signing since no option is available");
return;
}

83 changes: 82 additions & 1 deletion deployment/cake/generic-variables.cake
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ public class GeneralContext : BuildContextWithItemsBase
public SolutionContext Solution { get; set; }
public SourceLinkContext SourceLink { get; set; }
public CodeSignContext CodeSign { get; set; }
public AzureCodeSignContext AzureCodeSign { get; set; }
public RepositoryContext Repository { get; set; }
public SonarQubeContext SonarQube { get; set; }

@@ -338,14 +339,27 @@ public class CodeSignContext : BuildContextBase
public string TimeStampUri { get; set; }
public string HashAlgorithm { get; set; }

public bool IsAvailable
{
get
{
if (string.IsNullOrWhiteSpace(CertificateSubjectName))
{
return false;
}

return true;
}
}

protected override void ValidateContext()
{

}

protected override void LogStateInfoForContext()
{
if (string.IsNullOrWhiteSpace(CertificateSubjectName))
if (!IsAvailable)
{
CakeContext.Information($"Code signing is not configured");
return;
@@ -359,6 +373,62 @@ public class CodeSignContext : BuildContextBase

//-------------------------------------------------------------

public class AzureCodeSignContext : BuildContextBase
{
public AzureCodeSignContext(IBuildContext parentBuildContext)
: base(parentBuildContext)
{
}

public string VaultName { get; set; }
public string VaultUrl { get { return $"https://{VaultName}.vault.azure.net"; } }
public string CertificateName { get; set; }
public string TimeStampUri { get; set; }
public string HashAlgorithm { get; set; }
public string TenantId { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }

public bool IsAvailable
{
get
{
if (string.IsNullOrWhiteSpace(VaultName) ||
string.IsNullOrWhiteSpace(CertificateName) ||
string.IsNullOrWhiteSpace(TenantId) ||
string.IsNullOrWhiteSpace(ClientId) ||
string.IsNullOrWhiteSpace(ClientSecret))
{
return false;
}

return true;
}
}

protected override void ValidateContext()
{

}

protected override void LogStateInfoForContext()
{
if (!IsAvailable)
{
CakeContext.Information($"Azure Code signing is not configured");
return;
}

CakeContext.Information($"Azure Code vault name: '{VaultName}'");
CakeContext.Information($"Azure Code vault URL: '{VaultUrl}'");
CakeContext.Information($"Azure Code signing certificate name: '{CertificateName}'");
CakeContext.Information($"Azure Code signing timestamp uri: '{TimeStampUri}'");
CakeContext.Information($"Azure Code signing hash algorithm: '{HashAlgorithm}'");
}
}

//-------------------------------------------------------------

public class RepositoryContext : BuildContextBase
{
public RepositoryContext(IBuildContext parentBuildContext)
@@ -498,6 +568,17 @@ private GeneralContext InitializeGeneralContext(BuildContext buildContext, IBuil
HashAlgorithm = buildContext.BuildServer.GetVariable("CodeSignHashAlgorithm", "SHA256", showValue: true)
};

data.AzureCodeSign = new AzureCodeSignContext(data)
{
VaultName = buildContext.BuildServer.GetVariable("AzureCodeSignVaultName", showValue: true),
CertificateName = buildContext.BuildServer.GetVariable("AzureCodeSignCertificateName", showValue: true),
TimeStampUri = buildContext.BuildServer.GetVariable("AzureCodeSignTimeStampUri", "http://timestamp.digicert.com", showValue: true),
HashAlgorithm = buildContext.BuildServer.GetVariable("AzureCodeSignHashAlgorithm", "SHA256", showValue: true),
TenantId = buildContext.BuildServer.GetVariable("AzureCodeSignTenantId", showValue: false),
ClientId = buildContext.BuildServer.GetVariable("AzureCodeSignClientId", showValue: false),
ClientSecret = buildContext.BuildServer.GetVariable("AzureCodeSignClientSecret", showValue: false),
};

data.Repository = new RepositoryContext(data)
{
Url = buildContext.BuildServer.GetVariable("RepositoryUrl", showValue: true),
120 changes: 100 additions & 20 deletions deployment/cake/installers-innosetup.cake
Original file line number Diff line number Diff line change
@@ -73,33 +73,64 @@ public class InnoSetupInstaller : IInstaller
fileContents = fileContents.Replace("[VERSION_DISPLAY]", BuildContext.General.Version.FullSemVer);
fileContents = fileContents.Replace("[WIZARDIMAGEFILE]", string.Format("logo_large{0}", setupSuffix));

var signTool = string.Empty;
if (!string.IsNullOrWhiteSpace(BuildContext.General.CodeSign.CertificateSubjectName))
var signToolIndex = GetRandomSignToolIndex();

try
{
signTool = string.Format("SignTool={0}", BuildContext.General.CodeSign.CertificateSubjectName);
}
var codeSignContext = BuildContext.General.CodeSign;
var azureCodeSignContext = BuildContext.General.AzureCodeSign;

var signTool = string.Empty;

fileContents = fileContents.Replace("[SIGNTOOL]", signTool);
System.IO.File.WriteAllText(innoSetupScriptFileName, fileContents);
var signToolFileName = GetSignToolFileName(BuildContext);
if (!string.IsNullOrWhiteSpace(signToolFileName))
{
var signToolName = DateTime.Now.ToString("yyyyMMddHHmmss");
var signToolCommandLine = GetSignToolCommandLine(BuildContext);

BuildContext.CakeContext.Information("Generating Inno Setup packages, this can take a while, especially when signing is enabled...");
BuildContext.CakeContext.Information("Adding random sign tool config for Inno Setup");

BuildContext.CakeContext.InnoSetup(innoSetupScriptFileName, new InnoSetupSettings
{
OutputDirectory = innoSetupReleasesRoot
});
using (var registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(GetRegistryKey(), true))
{
var registryValueName = GetSignToolIndexName(signToolIndex);

if (BuildContext.Wpf.UpdateDeploymentsShare)
{
BuildContext.CakeContext.Information("Copying Inno Setup files to deployments share at '{0}'", installersOnDeploymentsShare);
// Important: must end with "$f"
var signToolRegistryValue = $"{signToolName}=\"{signToolFileName}\" {signToolCommandLine} \"$f\"";

// Copy the following files:
// - Setup.exe => [projectName]-[version].exe
// - Setup.exe => [projectName]-[channel].exe
registryKey.SetValue(registryValueName, signToolRegistryValue);
}

signTool = string.Format("SignTool={0}", signToolName);
}

fileContents = fileContents.Replace("[SIGNTOOL]", signTool);
System.IO.File.WriteAllText(innoSetupScriptFileName, fileContents);

BuildContext.CakeContext.Information("Generating Inno Setup packages, this can take a while, especially when signing is enabled...");

BuildContext.CakeContext.InnoSetup(innoSetupScriptFileName, new InnoSetupSettings
{
OutputDirectory = innoSetupReleasesRoot
});

var installerSourceFile = System.IO.Path.Combine(innoSetupReleasesRoot, $"{projectName}_{BuildContext.General.Version.FullSemVer}.exe");
BuildContext.CakeContext.CopyFile(installerSourceFile, System.IO.Path.Combine(installersOnDeploymentsShare, $"{projectName}_{BuildContext.General.Version.FullSemVer}.exe"));
BuildContext.CakeContext.CopyFile(installerSourceFile, System.IO.Path.Combine(installersOnDeploymentsShare, $"{projectName}{setupSuffix}.exe"));
if (BuildContext.Wpf.UpdateDeploymentsShare)
{
BuildContext.CakeContext.Information("Copying Inno Setup files to deployments share at '{0}'", installersOnDeploymentsShare);

// Copy the following files:
// - Setup.exe => [projectName]-[version].exe
// - Setup.exe => [projectName]-[channel].exe

var installerSourceFile = System.IO.Path.Combine(innoSetupReleasesRoot, $"{projectName}_{BuildContext.General.Version.FullSemVer}.exe");
BuildContext.CakeContext.CopyFile(installerSourceFile, System.IO.Path.Combine(installersOnDeploymentsShare, $"{projectName}_{BuildContext.General.Version.FullSemVer}.exe"));
BuildContext.CakeContext.CopyFile(installerSourceFile, System.IO.Path.Combine(installersOnDeploymentsShare, $"{projectName}{setupSuffix}.exe"));
}
}
finally
{
BuildContext.CakeContext.Information("Removing random sign tool config for Inno Setup");

RemoveSignToolFromRegistry(signToolIndex);
}
}

@@ -222,4 +253,53 @@ public class InnoSetupInstaller : IInstaller

return installersOnDeploymentsShare;
}

//-------------------------------------------------------------

private string GetRegistryKey()
{
return "Software\\Jordan Russell\\Inno Setup\\SignTools";
}

//-------------------------------------------------------------

private int GetRandomSignToolIndex()
{
using (var registryKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(GetRegistryKey()))
{
for (int i = 0; i < 100; i++)
{
var valueName = GetSignToolIndexName(i);

if (registryKey.GetValue(valueName) is null)
{
// Immediately lock it
registryKey.SetValue(valueName, "reserved");

return i;
}
}
}

throw new Exception("Could not find any empty slots for the sign tool, please clean up the sign tool registry for Inno Setup");
}

//-------------------------------------------------------------

private string GetSignToolIndexName(int index)
{
return $"SignTool{index}";
}

//-------------------------------------------------------------

private void RemoveSignToolFromRegistry(int index)
{
using (var registryKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(GetRegistryKey()))
{
var valueName = GetSignToolIndexName(index);

registryKey.DeleteValue(valueName, false);
}
}
}
Loading

Unchanged files with check annotations Beta

{
public ConfigurationAnalyticsValue(ConfigurationContainer container, string key, object? defaultValue)
{
ArgumentNullException.ThrowIfNull(container);

Check failure on line 10 in src/Orc.Analytics/Models/ConfigurationAnalyticsValue.cs

GitHub Actions / build-and-test

Calling 'ArgumentNullException.ThrowIfNull' and passing a non-nullable value is a no-op (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2264)

Check failure on line 10 in src/Orc.Analytics/Models/ConfigurationAnalyticsValue.cs

GitHub Actions / build-and-test

Calling 'ArgumentNullException.ThrowIfNull' and passing a non-nullable value is a no-op (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2264)
Category = "Configuration";
Container = container;