The main theme here is that code signing will be done in the outermost
executable project, not in any app extension projects or watch projects, nor
during the RID-specific build of a .NET universal app. This makes codesigning
easier to reason about and other affected logic (such as strip/dsymutil)
easier to handle, in particular for .NET universal apps. Another benefit is
that the differences between the iOS and macOS code bases have been
eliminated.

The first step is to collect all the information we need from the targets
files. Every app bundle (be it app extension, watch app or main app) will add
its own output app bundle (.app/.appex) to the _CodesignBundle item group.
Then every app bundle will load this informarion from referenced app bundles,
and finally store this information on disk (in the 'codesign-bundle.items'
file). This means that in the end the main app bundle will have a list of all
contained app bundles in the app (recursively), in the _CodesignBundle item
group.

Separately we keep a list of other items that need signing, in the
_CodesignItems item group, and we do the same store/load logic for every
contained/contained app bundle (in the 'codesign.items' file, so a the end the
main app bundle will have a list of all the _CodesignItems for all contained
app bundles (recursively).

The previous steps occur in the _CollectCodesigningData and
_StoreCodesigningData targets.

The next step is to use the new ComputeCodesignItems task to compute
everything we need to know for code signing. This task takes over the
responsibility for listing all the *.dylib and *.metallib files, and the
*.framework directories in the app bundles, that need signing (which was
previously done in the targets file). This logic is significantly easier to
write, debug and test in C# than MSBuild.

In addition the ComputeCodesignItems also figures out a stamp file path we use
to determine if something needs (re-)signing. Previously .framework
directories did not have a stamp location, so they'd always end up resigned in
a rebuild, while now we'll automatically skip signing *.framework directories
unless something changed in them.

I've also tried to comment everything thorougly, for the next poor soul having
to deal with any bugs.

Behavioral differences:

* We were always signing *.dylib files for macOS. We're now doing the same
  thing for all platforms.
* We're now always signing *.framework directories for all platforms (like we
  do for *.dylib files), since frameworks are pretty much like dylibs anyways.

I've verified that this works both by running the submission tests and running
and launching a sample project on device from Windows.
This commit is contained in:
Rolf Bjarne Kvinge 2022-03-22 12:53:58 +01:00 коммит произвёл GitHub
Родитель 45b8df6860 5d36a7ed4a
Коммит 7d500da2bf
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 1037 добавлений и 304 удалений

Просмотреть файл

@ -8,5 +8,12 @@ namespace Microsoft.Build.Framework {
item.GetMetadata ("ResolvedFrom") == "{TargetFrameworkDirectory}" ||
item.GetMetadata ("ResolvedFrom") == "ImplicitlyExpandDesignTimeFacades";
}
public static void SetMetadataIfNotSet (this ITaskItem self, string metadata, string value)
{
if (!string.IsNullOrEmpty (self.GetMetadata (metadata)))
return;
self.SetMetadata (metadata, value);
}
}
}

Просмотреть файл

@ -154,6 +154,40 @@ namespace Xamarin.MacDev.Tasks
return string.Equals (metadataValue, "true", StringComparison.OrdinalIgnoreCase);
}
string ResolvePath (ITaskItem item, string path)
{
if (string.IsNullOrEmpty (path))
return path;
path = PathUtils.ConvertToMacPath (path);
if (Path.IsPathRooted (path))
return path;
var sourceProjectPath = GetNonEmptyStringOrFallback (item, "SourceProjectPath", null);
if (sourceProjectPath is null)
return path;
return Path.Combine (sourceProjectPath, path);
}
string GetCodesignResourceRules (ITaskItem item)
{
var rv = GetNonEmptyStringOrFallback (item, "CodesignResourceRules", out var foundInMetadata, ResourceRules);
// The ResourceRules value is a path, and as such it might be a relative path from a different project, in which case we have to resolve it accordingly.
if (foundInMetadata)
rv = ResolvePath (item, rv);
return rv;
}
string GetCodesignEntitlements (ITaskItem item)
{
var rv = GetNonEmptyStringOrFallback (item, "CodesignEntitlements", out var foundInMetadata, ResourceRules);
// The ResourceRules value is a path, and as such it might be a relative path from a different project, in which case we have to resolve it accordingly.
if (foundInMetadata)
rv = ResolvePath (item, rv);
return rv;
}
IList<string> GenerateCommandLineArguments (ITaskItem item)
{
var args = new List<string> ();
@ -163,8 +197,8 @@ namespace Xamarin.MacDev.Tasks
var disableTimestamp = ParseBoolean (item, "CodesignDisableTimestamp", DisableTimestamp);
var signingKey = GetNonEmptyStringOrFallback (item, "CodesignSigningKey", SigningKey, "SigningKey", required: true);
var keychain = GetNonEmptyStringOrFallback (item, "CodesignKeychain", Keychain);
var resourceRules = GetNonEmptyStringOrFallback (item, "CodesignResourceRules", ResourceRules);
var entitlements = GetNonEmptyStringOrFallback (item, "CodesignEntitlements", Entitlements);
var resourceRules = GetCodesignResourceRules (item);
var entitlements = GetCodesignEntitlements (item);
var extraArgs = GetNonEmptyStringOrFallback (item, "CodesignExtraArgs", ExtraArgs);
args.Add ("-v");

Просмотреть файл

@ -0,0 +1,205 @@
using System;
using System.IO;
using System.Collections.Generic;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Xamarin.Localization.MSBuild;
using Xamarin.Utils;
#nullable enable
namespace Xamarin.MacDev.Tasks {
//
// This task is responsible for computing everything we need to know for code
// signing.
//
// For each app bundle to be signed, a few more items to be code signed:
//
// * All *.dylib and *.metallib files
// * All *.framework directories
//
// In both cases we iterate over what we find in the app bundle instead of
// relying on what the msbuild tasks built and copied in the app bundle,
// because customer logic might have added additional frameworks, and those
// need to be signed too.
//
// This task will also figure out a stamp file path we use to determine if
// something needs (re-)signing.
//
public abstract class ComputeCodesignItemsTaskBase : XamarinTask {
[Required]
public string AppBundleDir { get; set; } = string.Empty;
[Required]
public ITaskItem [] CodesignBundle { get; set; } = Array.Empty<ITaskItem> ();
[Required]
public ITaskItem [] CodesignItems { get; set; } = Array.Empty<ITaskItem> ();
[Required]
public string CodesignStampPath { get; set; } = string.Empty;
[Output]
public ITaskItem[] OutputCodesignItems { get; set; } = Array.Empty<ITaskItem> ();
public override bool Execute ()
{
var output = new List<ITaskItem> ();
// Make sure AppBundleDir has a trailing slash
var appBundlePath = PathUtils.EnsureTrailingSlash (Path.GetFullPath (AppBundleDir));
// Add the app bundles themselves
foreach (var bundle in CodesignBundle) {
// An app bundle is signed if either 'RequireCodeSigning' is true
// or a 'CodesignSigningKey' has been provided.
var requireCodeSigning = bundle.GetMetadata ("RequireCodeSigning");
var codesignSigningKey = bundle.GetMetadata ("CodesignSigningKey");
if (!string.Equals (requireCodeSigning, "true") && string.IsNullOrEmpty (codesignSigningKey))
continue;
// Create a new item for the app bundle, and copy any metadata over.
var bundlePath = Path.Combine (Path.GetDirectoryName (AppBundleDir), bundle.ItemSpec);
var item = new TaskItem (bundlePath);
bundle.CopyMetadataTo (item);
// Compute the stamp file to use
item.SetMetadataIfNotSet ("CodesignStampFile", Path.Combine (bundlePath, CodeSignatureRelativePath, "_CodeSignature", "CodeResources"));
// Get any additional stamp files we must touch when the item is signed.
var additionalStampFiles = new List<string> ();
// We must touch the dSYM directory's Info.plist, to ensure that we don't end up running dsymutil again after codesigning in the next build
var dSYMUtilStampFile = Path.Combine (Path.GetDirectoryName (AppBundleDir), Path.GetFileName (item.ItemSpec) + ".dSYM", "Contents", "Info.plist");
additionalStampFiles.Add (dSYMUtilStampFile);
// Set the CodesignAdditionalFilesToTouch metadata (merge with any existing values)
if (additionalStampFiles.Count > 0) {
additionalStampFiles.AddRange (item.GetMetadata ("CodesignAdditionalFilesToTouch").Split (','));
additionalStampFiles.RemoveAll (v => string.IsNullOrEmpty (v));
item.SetMetadata ("CodesignAdditionalFilesToTouch", string.Join (";", additionalStampFiles));
}
output.Add (item);
}
// Find all:
// - *.dylib and *.metallib files
// - *.framework directories
foreach (var bundle in CodesignBundle) {
var bundlePath = Path.Combine (Path.GetDirectoryName (Path.GetDirectoryName (appBundlePath)), bundle.ItemSpec);
var filesToSign = FindFilesToSign (bundlePath);
foreach (var lib in filesToSign) {
var relativeLib = Path.Combine (AppBundleDir, lib.Substring (appBundlePath.Length));
var item = new TaskItem (relativeLib);
bundle.CopyMetadataTo (item);
// These items must not use the entitlements for the app
item.RemoveMetadata ("CodesignEntitlements");
// These files are a bit special, because they're always signed. This is done
// by setting the signing key to '-' if it's not set.
item.SetMetadataIfNotSet ("CodesignSigningKey", "-");
// Set the stamp file even if already set (because any existing values would be copied from
// the bundle, which would be the wrong stamp file, so it must be overridden)
if (Directory.Exists (relativeLib)) {
item.SetMetadata ("CodesignStampFile", Path.Combine (CodesignStampPath, relativeLib, ".stampfile"));
} else {
item.SetMetadata ("CodesignStampFile", Path.Combine (CodesignStampPath, relativeLib));
}
output.Add (item);
}
}
// Add all additional items
foreach (var item in CodesignItems) {
// Set the stamp file if not already set.
item.SetMetadataIfNotSet ("CodesignStampFile", Path.Combine (CodesignStampPath, item.ItemSpec));
output.Add (item);
}
OutputCodesignItems = output.ToArray ();
return !Log.HasLoggedErrors;
}
string CodeSignatureRelativePath {
get {
switch (Platform) {
case ApplePlatform.iOS:
case ApplePlatform.TVOS:
case ApplePlatform.WatchOS:
return string.Empty;
case ApplePlatform.MacOSX:
case ApplePlatform.MacCatalyst:
return "Contents";
default:
throw new InvalidOperationException (string.Format (MSBStrings.InvalidPlatform, Platform));
}
}
}
IEnumerable<string> FindFilesToSign (string appPath)
{
var rv = new List<string> ();
// Canonicalize the app path, so string comparisons work later on
appPath = PathUtils.ResolveSymbolicLinks (Path.GetFullPath (appPath));
// Make sure path ends with trailing slash to ease logic
appPath = PathUtils.EnsureTrailingSlash (appPath);
string dylibDirectory;
string metallibDirectory;
string frameworksDirectory;
switch (Platform) {
case ApplePlatform.iOS:
case ApplePlatform.TVOS:
case ApplePlatform.WatchOS:
dylibDirectory = appPath;
metallibDirectory = appPath;
frameworksDirectory = Path.Combine (appPath, "Frameworks");
break;
case ApplePlatform.MacOSX:
case ApplePlatform.MacCatalyst:
dylibDirectory = Path.Combine (appPath, "Contents");
metallibDirectory = Path.Combine (appPath, "Contents", "Resources");
frameworksDirectory = Path.Combine (appPath, "Contents", "Frameworks");
break;
default:
throw new InvalidOperationException (string.Format (MSBStrings.InvalidPlatform, Platform));
}
dylibDirectory = PathUtils.EnsureTrailingSlash (dylibDirectory);
metallibDirectory = PathUtils.EnsureTrailingSlash (metallibDirectory);
foreach (var entry in Directory.EnumerateFileSystemEntries (appPath, "*", SearchOption.AllDirectories)) {
var relativePath = entry.Substring (appPath.Length);
// Don't recurse into the PlugIns directory, that's already handled for any app bundle inside the PlugIns directory
if (relativePath.StartsWith ("PlugIns" + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
continue;
// Don't recurse into the Watch directory, for the same reason
if (relativePath.StartsWith ("Watch" + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
continue;
if (entry.EndsWith (".dylib", StringComparison.OrdinalIgnoreCase) && entry.StartsWith (dylibDirectory, StringComparison.OrdinalIgnoreCase)) {
// We find *.dylibs in any subdirectory
rv.Add (entry);
} else if (entry.EndsWith (".metallib", StringComparison.OrdinalIgnoreCase) && entry.StartsWith (metallibDirectory, StringComparison.OrdinalIgnoreCase)) {
// We find *.metallib in any subdirectory
rv.Add (entry);
} else if (entry.EndsWith (".framework", StringComparison.OrdinalIgnoreCase) && string.Equals (Path.GetDirectoryName (entry), frameworksDirectory, StringComparison.OrdinalIgnoreCase)) {
// We only find *.frameworks inside the Frameworks subdirectory, not recursively
// (not quite sure if this is the right thing to do, but it's what we've been doing so far).
rv.Add (entry);
}
}
return rv;
}
}
}

Просмотреть файл

@ -154,12 +154,20 @@ namespace Xamarin.MacDev.Tasks {
}
protected string GetNonEmptyStringOrFallback (ITaskItem item, string metadataName, string fallbackValue, string fallbackName = null, bool required = false)
{
return GetNonEmptyStringOrFallback (item, metadataName, out var _, fallbackValue, fallbackName, required);
}
protected string GetNonEmptyStringOrFallback (ITaskItem item, string metadataName, out bool foundInMetadata, string fallbackValue, string fallbackName = null, bool required = false)
{
var metadataValue = item.GetMetadata (metadataName);
if (!string.IsNullOrEmpty (metadataValue))
if (!string.IsNullOrEmpty (metadataValue)) {
foundInMetadata = true;
return metadataValue;
}
if (required && string.IsNullOrEmpty (fallbackValue))
Log.LogError (MSBStrings.E7085 /* The "{0}" task was not given a value for the required parameter "{1}", nor was there a "{2}" metadata on the resource {3}. */, GetType ().Name, fallbackName ?? metadataName, metadataName, item.ItemSpec);
foundInMetadata = false;
return fallbackValue;
}
}

Просмотреть файл

@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Build.Framework;
using Xamarin.Messaging.Build.Client;
namespace Xamarin.MacDev.Tasks {
public class ComputeCodesignItems : ComputeCodesignItemsTaskBase, ITaskCallback, ICancelableTask {
public override bool Execute ()
{
if (ShouldExecuteRemotely ())
return new TaskRunner (SessionId, BuildEngine4).RunAsync (this).Result;
return base.Execute ();
}
public IEnumerable<ITaskItem> GetAdditionalItemsToBeCopied () => Enumerable.Empty<ITaskItem> ();
// This task does not create or modify any files, and it should only
// deal with files that are already on the mac, so no need to copy any
// files either way.
public bool ShouldCopyToBuildServer (ITaskItem item) => false;
public bool ShouldCreateOutputFile (ITaskItem item) => false;
public void Cancel ()
{
if (ShouldExecuteRemotely ())
BuildConnection.CancelAsync (SessionId, BuildEngine4).Wait ();
}
}
}

Просмотреть файл

@ -87,6 +87,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<UsingTask TaskName="Xamarin.MacDev.Tasks.CreateInstallerPackage" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.CreatePkgInfo" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.CompileProductDefinition" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.ComputeCodesignItems" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.DetectDebugNetworkConfiguration" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.Ditto" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.DSymUtil" AssemblyFile="$(_TaskAssemblyName)" />
@ -374,7 +375,8 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<_IpaPackageFile Include="$(DeviceSpecificOutputPath)*.ipa" />
</ItemGroup>
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true' And '$(IsAppExtension)' == 'true'" Files="$(DeviceSpecificOutputPath)codesign.items" />
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="$(DeviceSpecificOutputPath)codesign.items" />
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="$(DeviceSpecificOutputPath)codesign-bundle.items" />
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="@(_IpaPackageFile)" />
</Target>
@ -614,7 +616,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
</PropertyGroup>
<Target Name="_CompileEntitlements"
Condition="'$(_RequireCodeSigning)' == 'true' Or ('$(CodesignEntitlements)' != '' And '$(_PlatformName)' != 'macOS')"
Condition="'$(_RequireCodeSigning)' == 'true' Or '$(CodesignEntitlements)' != ''"
DependsOnTargets="$(_CompileEntitlementsDependsOn)"
Outputs="$(DeviceSpecificIntermediateOutputPath)Entitlements.xcent">
<CompileEntitlements
@ -638,9 +640,19 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<!-- $(_CompiledEntitlements) will be passed to the MTouch task, it's used to embed the entitlements in the executable -->
<Output TaskParameter="EntitlementsInExecutable" PropertyName="_CompiledEntitlements" />
<!-- $(_CompiledCodesignEntitlements) will be used only with Codesign tasks when building for device. MUST NOT BE SET for iOS Simulator builds. -->
<!-- $(_CompiledCodesignEntitlements) will be used only with Codesign tasks when building for device or desktop. MUST NOT BE SET for iOS Simulator builds. -->
<Output TaskParameter="EntitlementsInSignature" PropertyName="_CompiledCodesignEntitlements" />
</CompileEntitlements>
<!-- The path to the entitlements must be resolved to the full path, because we might want to reference it from a containing project that just references this project,
and in that case it becomes a bit complicated to resolve to a full path on disk when building remotely from Windows. Instead just resolve to a full path here,
and use that from now on. This has to be done from a task, so that we get the full path on the mac when executed remotely from Windows. -->
<GetFullPath SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true' And '$(_CompiledEntitlements)' != ''" RelativePath="$(_CompiledEntitlements)">
<Output TaskParameter="FullPath" PropertyName="_CompiledEntitlements" />
</GetFullPath>
<GetFullPath SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true' And '$(_CompiledCodesignEntitlements)' != ''" RelativePath="$(_CompiledCodesignEntitlements)">
<Output TaskParameter="FullPath" PropertyName="_CompiledCodesignEntitlements" />
</GetFullPath>
</Target>
<!-- Compilation of InterfaceDefinition assets (*.xib, *.storyboard) -->
@ -1754,17 +1766,21 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<!-- Code signing -->
<PropertyGroup>
<_CollectCodesigningDataDependsOn>
$(_CollectCodesigningData);
_PlaceAppExtensions;
</_CollectCodesigningDataDependsOn>
<_CollectCodesigningDataDependsOn Condition="'$(_PlatformName)' != 'macOS'">
$(_CollectCodesigningData);
_ResolveWatchAppReferences;
</_CollectCodesigningDataDependsOn>
<_CodesignAppBundleDependsOn>
$(_CodesignAppBundleDependsOn);
_CleanAppBundleRootDirectory;
_EmbedProvisionProfile;
_CodesignNativeLibraries;
_CollectFrameworks;
_CodesignFrameworks;
_ReadAppExtensionCodesignProperties;
_CodesignAppExtensions;
_PrepareCodesignAppExtension;
_CalculateCodesignAppBundleInputs;
_CollectCodesigningData;
_StoreCodesigningData;
</_CodesignAppBundleDependsOn>
<CoreCodesignDependsOn>
@ -1789,87 +1805,245 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<Target Name="Codesign" Condition="'$(_CanOutputAppBundle)' == 'true'" DependsOnTargets="$(CodesignDependsOn)" />
<PropertyGroup>
<_CodesignNativeLibrariesDependsOn>
$(_CodesignNativeLibrariesDependsOn);
_DetectSigningIdentity;
_CompileToNative;
_PlaceAppExtensions;
</_CodesignNativeLibrariesDependsOn>
</PropertyGroup>
<!--
Code signing
============
A main point in code signing is that signing will be done in the
outermost executable project, not in any app extension projects or
watch projects, nor during the RID-specific build of a universal .NET
app. This makes codesigning easier to reason about and other affected
logic (such as strip/dsymutil) easier to handle, in particular for
.NET universal apps.
The first step is to collect all the information we need from the
targets files. Every app bundle (be it app extension, watch app or
main app) will add its own output app bundle (.app/.appex) to the
_CodesignBundle item group. Then every app bundle will load this
information from referenced app bundles, and finally store this
information on disk (in the 'codesign-bundle.items' file). This means
that in the end the main app bundle will have a list of all contained
app bundles in the app (recursively), in the _CodesignBundle item
group.
Separately we keep a list of other items that need signing, in the
_CodesignItems item group, and we do the same store/load logic for
every contained/contained app bundle (in the 'codesign.items' file, so
a the end the main app bundle will have a list of all the
_CodesignItems for all contained app bundles (recursively).
The previous steps occur in the _CollectCodesigningData and
_StoreCodesigningData targets.
The next step is to use the ComputeCodesignItems task to compute
everything we need to know for code signing. This task has the
responsibility for listing all the *.dylib and *.metallib files, and
the *.framework directories in the app bundles, that need signing.
This logic is significantly easier to write, debug and test in C# than
MSBuild.
In addition the ComputeCodesignItems also figures out a stamp file
path we use to determine if something needs (re-)signing.
Finally we give the list of _ComputedCodesignItems to the Codesign
task for signing.
At the very end, and only if we signed the main app bundle, we verify
that the signature is correct (in the _CodesignVerify target).
<!-- Note:
Always codesign *.dylibs even for Simulator builds for iOS/tvOS/watchOS. We use $(_CanOutputAppBundle) because dylibs can exist in app extensions as well.
For macOS we sign if _RequireCodeSigning is true
-->
<Target Name="_CodesignNativeLibraries" Condition="'$(_CanOutputAppBundle)' == 'true' And ('$(_RequireCodeSigning)' == 'true' Or '$(_PlatformName)' != 'macOS')" DependsOnTargets="$(_CodesignNativeLibrariesDependsOn)">
<PropertyGroup>
<_CodesignDisableTimestamp>False</_CodesignDisableTimestamp>
<_CodesignDisableTimestamp Condition="'$(_SdkIsSimulator)' == 'true' Or '$(_BundlerDebug)' == 'true'">True</_CodesignDisableTimestamp>
<_LibraryCodeSigningKey>$(_CodeSigningKey)</_LibraryCodeSigningKey>
<_LibraryCodeSigningKey Condition="'$(_LibraryCodeSigningKey)' == ''">-</_LibraryCodeSigningKey>
</PropertyGroup>
<ItemGroup Condition="'$(_PlatformName)' == 'macOS' Or '$(_PlatformName)' == 'MacCatalyst'">
<_CodesignNativeLibrary Include="$(_AppContentsPath)\**\*.dylib" />
<_CodesignNativeLibrary Include="$(_AppResourcesPath)\**\*.metallib" />
</ItemGroup>
<ItemGroup Condition="'$(_PlatformName)' == 'iOS' Or '$(_PlatformName)' == 'tvOS' Or '$(_PlatformName)' == 'watchOS'">
<_CodesignNativeLibrary
Include="$(_AppBundlePath)\**\*.dylib;$(_AppBundlePath)\**\*.metallib"
Exclude="$(_AppBundlePath)\Watch\**;$(_AppExtensionRoot)\PlugIns\**"
/>
</ItemGroup>
<ItemGroup>
<_CodesignItems Include="@(_CodesignNativeLibrary)">
<CodesignAllocate>$(_CodesignAllocate)</CodesignAllocate>
<CodesignDeep>$(IsAppExtension)</CodesignDeep>
<CodesignDisableTimestamp>$(_CodesignDisableTimestamp)</CodesignDisableTimestamp>
<!-- CodesignEntitlements -->
<CodesignExtraArgs>$(CodesignExtraArgs)</CodesignExtraArgs>
<CodesignKeychain>$(CodesignKeychain)</CodesignKeychain>
<!-- CodesignResourceRules -->
<CodesignSigningKey>$(_LibraryCodeSigningKey)</CodesignSigningKey>
<CodesignStampPath>$(DeviceSpecificIntermediateOutputPath)codesign\</CodesignStampPath>
<!-- CodesignUseHardenedRuntime-->
<CodesignUseSecureTimestamp>$(UseHardenedRuntime)</CodesignUseSecureTimestamp>
</_CodesignItems>
</ItemGroup>
</Target>
<Target Name="_CodesignVerify" Condition="'$(_RequireCodeSigning)' == 'true' And ('$(IsAppExtension)' == 'false' Or '@(_ResolvedAppExtensionReferences)' != '')" DependsOnTargets="_CodesignAppBundle">
<CodesignVerify
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true' And '@(_ResolvedAppExtensionReferences)' != ''"
ToolExe="$(CodesignExe)"
ToolPath="$(CodesignPath)"
CodesignAllocate="$(_CodesignAllocate)"
Resource="$(_AppExtensionRoot)PlugIns\%(_ResolvedAppExtensionReferences.Filename)%(_ResolvedAppExtensionReferences.Extension)"
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
<!--
_CodesignVerify: verify that the app bundle we've produced is valid and signed properly.
This target is only executed for app bundles (and not when only dylibs and frameworks are signed, but the app bundle itself is not).
-->
<Target
Name="_CodesignVerify"
Condition="'$(_CodesignAppBundleCondition)' == 'true' And '$(_RequireCodeSigning)' == 'true'"
DependsOnTargets="_CodesignAppBundle"
>
</CodesignVerify>
<CodesignVerify
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
ToolExe="$(CodesignExe)"
ToolPath="$(CodesignPath)"
CodesignAllocate="$(_CodesignAllocate)"
Resource="$(AppBundleDir)"
Resource="$(_AppContainerDir)\%(_CodesignBundle.Identity)"
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
>
</CodesignVerify>
</Target>
<PropertyGroup>
<_CollectFrameworksDependsOn>
$(_CollectFrameworksDependsOn);
_DetectSigningIdentity;
_CompileToNative;
</_CollectFrameworksDependsOn>
</PropertyGroup>
<!--
_CollectCodesigningData: This target collects all the data required to sign the app bundle.
* We iterate over all app extensions, and load the signing data from
each of them (and since each app extension does the same thing, we
effectively end up collecting codesigning data from nested app
extensions as well).
* We load signing data from any watch apps (which already contains
codesigning data for the watch extension (and any other contained
extensions), we effectively end up collecting codesigning data
recursively).
* We add signing data for the current project's app bundle (if that's
what we're building).
Item groups:
* _CodesignBundle: all the bundles (*.app, *.appex) that must be
signed (including the watch app). The identity is relative to the
output directory where we put the app bundle (because this makes
it easy to update the identity when loading data from contained
projects - we just have to prepend the relative path to where the
contained app bundle is to be placed in the current app bundle)
* _CodesignItems: other files and directories that must be signed
(*.dylib, *.framework, createdump, etc.). The identity is the same
as for _CodesignBundle.
-->
<Target
Name="_CollectCodesigningData"
DependsOnTargets="$(_CollectCodesigningDataDependsOn)"
>
<!-- Get app bundles to sign from app extensions -->
<ReadItemsFromFile File="@(_ResolvedAppExtensionReferences->'%(Identity)\..\codesign-bundle.items')" Condition="Exists('%(Identity)\..\codesign-bundle.items')">
<Output TaskParameter="Items" ItemName="_CodesignAppExtensionBundle" />
</ReadItemsFromFile>
<ItemGroup>
<_CodesignBundle Include="@(_CodesignAppExtensionBundle->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)/%(Identity)')" />
</ItemGroup>
<!-- Get items to sign from app extensions -->
<ReadItemsFromFile File="@(_ResolvedAppExtensionReferences->'%(Identity)\..\codesign.items')" Condition="Exists('%(Identity)\..\codesign.items')">
<Output TaskParameter="Items" ItemName="_CodesignAppExtensionItem" />
</ReadItemsFromFile>
<ItemGroup>
<_CodesignItems Include="@(_CodesignAppExtensionItem->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)/%(Identity)')" />
</ItemGroup>
<!-- Get app bundles to sign from watch apps -->
<ReadItemsFromFile File="@(_ResolvedWatchAppReferences->'%(Identity)\..\codesign-bundle.items')" Condition="Exists('%(Identity)\..\codesign-bundle.items')">
<Output TaskParameter="Items" ItemName="_CodesignWatchBundle" />
</ReadItemsFromFile>
<ItemGroup>
<_CodesignBundle Include="@(_CodesignWatchBundle->'$(_AppBundleName)$(AppBundleExtension)/Watch/%(Identity)')" />
</ItemGroup>
<!-- Get items to sign from watch apps -->
<ReadItemsFromFile File="@(_ResolvedWatchAppReferences->'%(Identity)\..\codesign.items')" Condition="Exists('%(Identity)\..\codesign.items')">
<Output TaskParameter="Items" ItemName="_CodesignWatchItem" />
</ReadItemsFromFile>
<ItemGroup>
<_CodesignItems Include="@(_CodesignWatchItem->'$(_AppBundleName)$(AppBundleExtension)/Watch/%(Identity)')" />
</ItemGroup>
<!-- Add this app bundle to _CodesignBundle -->
<ItemGroup>
<_CodesignBundle Include="$(_AppBundleName)$(AppBundleExtension)">
<CodesignAllocate>$(_CodesignAllocate)</CodesignAllocate>
<CodesignDisableTimestamp>false</CodesignDisableTimestamp>
<CodesignDisableTimestamp Condition="'$(_SdkIsSimulator)' == 'true' Or '$(_BundlerDebug)' == 'true'">true</CodesignDisableTimestamp>
<CodesignEntitlements>$(_CompiledCodesignEntitlements)</CodesignEntitlements>
<CodesignExtraArgs>$(CodesignExtraArgs)</CodesignExtraArgs>
<CodesignKeychain>$(CodesignKeychain)</CodesignKeychain>
<CodesignResourceRules>$(_PreparedResourceRules)</CodesignResourceRules>
<CodesignSigningKey>$(_CodeSigningKey)</CodesignSigningKey>
<CodesignUseHardenedRuntime>$(UseHardenedRuntime)</CodesignUseHardenedRuntime>
<CodesignUseSecureTimestamp>$(UseHardenedRuntime)</CodesignUseSecureTimestamp>
<RequireCodeSigning>$(_RequireCodeSigning)</RequireCodeSigning>
<SourceProjectPath>$(MSBuildProjectDirectory)</SourceProjectPath>
</_CodesignBundle>
<!-- Set the SourceProjectPath metadata on all items that don't have it already -->
<_CodesignItems>
<SourceProjectPath Condition="'%(_CodesignItems.SourceProjectPath)' == ''">$(MSBuildProjectDirectory)</SourceProjectPath>
</_CodesignItems>
</ItemGroup>
<PropertyGroup>
<!--
We only run the CodesignAppBundle target on the outer-most executable project
* Not on app extensions
* Not on watch apps
-->
<_CodesignAppBundleCondition Condition="'$(_CodesignAppBundleCondition)' == '' And '$(IsAppExtension)' != 'true' And '$(IsWatchApp)' != 'true' And '$(_CanOutputAppBundle)' == 'true'">true</_CodesignAppBundleCondition>
<_CodesignAppBundleCondition Condition="'$(_CodesignAppBundleCondition)' == ''">false</_CodesignAppBundleCondition>
</PropertyGroup>
</Target>
<!-- This target writes all the properties required to sign items for this project, so that they can be read in containing projects.
The _CodesignBundle item group also contains items for contained projects this project may have (extension projects may have extension projects, etc.). -->
<Target
Name="_StoreCodesigningData"
DependsOnTargets="_CollectCodesigningData"
>
<WriteItemsToFile
Condition="'$(IsMacEnabled)' == 'true'"
SessionId="$(BuildSessionId)"
Items="@(_CodesignBundle)"
ItemName="_CodesignBundle"
File="$(DeviceSpecificOutputPath)codesign-bundle.items"
IncludeMetadata="true"
Overwrite="true"
/>
<WriteItemsToFile
Condition="'$(IsMacEnabled)' == 'true'"
SessionId="$(BuildSessionId)"
Items="@(_CodesignItems)"
ItemName="_CodesignItems"
File="$(DeviceSpecificOutputPath)codesign.items"
IncludeMetadata="true"
Overwrite="true"
/>
</Target>
<!--
_CodesignAppBundle: sign the app bundle and anything inside that needs
signing
This target does not have Inputs/Outputs, because computing what needs
signing or not is quite complex:
* The ComputeCodesignItems will add items to sign (this computation is
much easier to do in C# than here)
* If any file inside a directory has been modified, we need to
(re)sign
* If any file or directory inside a directory needs to be signed, then
the containing directory must be signed as well
This logic is implemented in the Codesign task.
-->
<Target Name="_CodesignAppBundle"
Condition="'$(_CodesignAppBundleCondition)' == 'true'"
DependsOnTargets="$(_CodesignAppBundleDependsOn)"
>
<ComputeCodesignItems
Condition="'$(IsMacEnabled)' == 'true'"
SessionId="$(BuildSessionId)"
AppBundleDir="$(AppBundleDir)"
CodesignBundle="@(_CodesignBundle)"
CodesignItems="@(_CodesignItems)"
CodesignStampPath="$(DeviceSpecificIntermediateOutputPath)codesign\"
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
>
<Output TaskParameter="OutputCodesignItems" ItemName="_ComputedCodesignItems" />
</ComputeCodesignItems>
<Codesign
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
Resources="@(_ComputedCodesignItems)"
ToolExe="$(CodesignExe)"
ToolPath="$(CodesignPath)"
>
</Codesign>
</Target>
<Target Name="_CollectFrameworks" Condition="'$(_CanOutputAppBundle)' == 'true'" DependsOnTargets="$(_CollectFrameworksDependsOn)">
<PropertyGroup>
@ -1889,229 +2063,6 @@ Copyright (C) 2018 Microsoft. All rights reserved.
</PropertyGroup>
</Target>
<Target Name="_CodesignFrameworks" Condition="'$(_MustCodesignFrameworks)' == 'true'" DependsOnTargets="_DetectSigningIdentity;_CollectFrameworks">
<PropertyGroup>
<_CodesignDisableTimestamp>False</_CodesignDisableTimestamp>
<_CodesignDisableTimestamp Condition="'$(_SdkIsSimulator)' == 'true' Or '$(_BundlerDebug)' == 'true'">True</_CodesignDisableTimestamp>
<_FrameworkCodeSigningKey>$(_CodeSigningKey)</_FrameworkCodeSigningKey>
<_FrameworkCodeSigningKey Condition="'$(_FrameworkCodeSigningKey)' == ''">-</_FrameworkCodeSigningKey>
</PropertyGroup>
<ItemGroup>
<_CodesignItems Include="@(_Frameworks)">
<CodesignAllocate>$(_CodesignAllocate)</CodesignAllocate>
<!-- CodesignDeep -->
<CodesignDisableTimestamp>$(_CodesignDisableTimestamp)</CodesignDisableTimestamp>
<!-- CodesignEntitlements -->
<CodesignExtraArgs>$(CodesignExtraArgs)</CodesignExtraArgs>
<CodesignKeychain>$(CodesignKeychain)</CodesignKeychain>
<!-- CodesignResourceRules -->
<CodesignSigningKey>$(_FrameworkCodeSigningKey)</CodesignSigningKey>
<!-- CodesignUseHardenedRuntime -->
<CodesignUseSecureTimestamp>$(UseHardenedRuntime)</CodesignUseSecureTimestamp>
</_CodesignItems>
</ItemGroup>
</Target>
<Target Name="_ReadAppExtensionCodesignProperties">
<ReadItemsFromFile File="%(_ResolvedAppExtensionReferences.Identity)\..\codesign.items" Condition="Exists('%(_ResolvedAppExtensionReferences.Identity)\..\codesign.items')">
<Output TaskParameter="Items" ItemName="_AppExtensionCodesignProperties" />
</ReadItemsFromFile>
</Target>
<Target Name="_CodesignAppExtensions"
Condition="'$(_CanOutputAppBundle)' == 'true' And '@(_AppExtensionCodesignProperties)' != ''"
DependsOnTargets="_DetectSigningIdentity;_ReadAppExtensionCodesignProperties"
>
<PropertyGroup>
<_CodesignAppExtensionsLibraryPath>$(_AppPlugInsPath)%(_AppExtensionCodesignProperties.Identity)\</_CodesignAppExtensionsLibraryPath>
</PropertyGroup>
<ItemGroup>
<_CodesignAppExtensionsLibrary
Include="$(_CodesignAppExtensionsLibraryPath)**\*.dylib;$(_CodesignAppExtensionsLibraryPath)**\*.metallib"
Exclude="$(_CodesignAppExtensionsLibraryPath)Watch\**;$(_CodesignAppExtensionsLibraryPath)$(_AppPlugInsRelativePath)\**"
>
</_CodesignAppExtensionsLibrary>
</ItemGroup>
<ItemGroup>
<_CodesignItems Include="@(_CodesignAppExtensionsLibrary)" Condition="'%(_AppExtensionCodesignProperties.LibrarySigningKey)' != ''">
<CodesignAllocate>%(_AppExtensionCodesignProperties.CodesignAllocate)</CodesignAllocate>
<!-- CodesignDeep -->
<CodesignDisableTimestamp>%(_AppExtensionCodesignProperties.DisableTimestamp)</CodesignDisableTimestamp>
<!-- CodesignEntitlements -->
<CodesignExtraArgs>%(_AppExtensionCodesignProperties.ExtraArgs)</CodesignExtraArgs>
<CodesignKeychain>%(_AppExtensionCodesignProperties.Keychain)</CodesignKeychain>
<!-- CodesignResourceRules -->
<CodesignSigningKey>%(_AppExtensionCodesignProperties.LibrarySigningKey)</CodesignSigningKey>
<CodesignStampPath>$(DeviceSpecificIntermediateOutputPath)codesign\PlugIns\%(_AppExtensionCodesignProperties.Identity)</CodesignStampPath>
<!-- CodesignUseHardenedRuntime -->
<!-- CodesignUseSecureTimestamp -->
</_CodesignItems>
</ItemGroup>
<ItemGroup>
<_CodesignItems Include="$(_AppPlugInsPath)%(_AppExtensionCodesignProperties.Identity)" Condition="'%(_AppExtensionCodesignProperties.SigningKey)' != ''">
<CodesignAllocate>%(_AppExtensionCodesignProperties.CodesignAllocate)</CodesignAllocate>
<!-- CodesignDeep -->
<CodesignDisableTimestamp>%(_AppExtensionCodesignProperties.DisableTimestamp)</CodesignDisableTimestamp>
<CodesignEntitlements>%(_AppExtensionCodesignProperties.Entitlements)</CodesignEntitlements>
<CodesignExtraArgs>%(_AppExtensionCodesignProperties.ExtraArgs)</CodesignExtraArgs>
<CodesignKeychain>%(_AppExtensionCodesignProperties.Keychain)</CodesignKeychain>
<CodesignResourceRules>%(_AppExtensionCodesignProperties.ResourceRules)</CodesignResourceRules>
<CodesignSigningKey>%(_AppExtensionCodesignProperties.SigningKey)</CodesignSigningKey>
<!-- CodesignStampPath -->
<!-- CodesignUseHardenedRuntime -->
<!-- CodesignUseSecureTimestamp -->
</_CodesignItems>
</ItemGroup>
</Target>
<Target Name="_PrepareCodesignAppExtension" Condition="'$(_CanOutputAppBundle)' == 'true' And '$(IsAppExtension)' == 'true' And '@(_ResolvedAppBundleExtensions)' == ''">
<!-- For App Extensions, we delay running codesign until it has been copied into the main app bundle... -->
<PropertyGroup>
<_CompiledEntitlementsFullPath></_CompiledEntitlementsFullPath>
<_ResourceRulesFullPath></_ResourceRulesFullPath>
</PropertyGroup>
<GetFullPath SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" RelativePath="$(AppBundleDir)">
<Output TaskParameter="FullPath" PropertyName="_AppBundleFullPath" />
</GetFullPath>
<GetFullPath SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true' And '$(_CompiledCodesignEntitlements)' != ''" RelativePath="$(_CompiledCodesignEntitlements)">
<Output TaskParameter="FullPath" PropertyName="_CompiledEntitlementsFullPath" />
</GetFullPath>
<GetFullPath SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true' And '$(_PreparedResourceRules)' != ''" RelativePath="$(_PreparedResourceRules)">
<Output TaskParameter="FullPath" PropertyName="_ResourceRulesFullPath" />
</GetFullPath>
<GetFiles SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Path="$(_AppBundleFullPath)" Pattern="*.*" Option="AllDirectories">
<Output TaskParameter="Files" ItemName="_AppExtensionBundleFiles" />
</GetFiles>
<PropertyGroup>
<!-- [System.IO.Path]::GetFileName() is safe to use -->
<_AppBundleFileName>$([System.IO.Path]::GetFileName('$(AppBundleDir)'))</_AppBundleFileName>
<_NativeExecutableFileName>$([System.IO.Path]::GetFileName('$(_NativeExecutable)'))</_NativeExecutableFileName>
<_CodesignDisableTimestamp>False</_CodesignDisableTimestamp>
<_CodesignDisableTimestamp Condition="'$(_SdkIsSimulator)' == 'true' Or '$(_BundlerDebug)' == 'true'">True</_CodesignDisableTimestamp>
<_CodesignAppExtensionInputs>@(_AppExtensionBundleFiles);$(_EntitlementsFullPath)</_CodesignAppExtensionInputs>
<_LibrarySigningKey>$(_CodeSigningKey)</_LibrarySigningKey>
<_LibrarySigningKey Condition="'$(_LibrarySigningKey)' == ''">-</_LibrarySigningKey>
</PropertyGroup>
<ItemGroup>
<_AppExtensionCodesignPropertiesToWrite Include="$(_AppBundleFileName)">
<CodesignAppExtensionInputs>$(_CodesignAppExtensionInputs)</CodesignAppExtensionInputs>
<NativeExecutable>$(_NativeExecutableFileName)</NativeExecutable>
<CodesignAllocate>$(_CodesignAllocate)</CodesignAllocate>
<DisableTimestamp>$(_CodesignDisableTimestamp)</DisableTimestamp>
<Entitlements>$(_CompiledEntitlementsFullPath)</Entitlements>
<ResourceRules>$(_ResourceRulesFullPath)</ResourceRules>
<Keychain>$(CodesignKeychain)</Keychain>
<LibrarySigningKey>$(_LibrarySigningKey)</LibrarySigningKey>
<SigningKey>$(_CodeSigningKey)</SigningKey>
<ExtraArgs>$(CodesignExtraArgs)</ExtraArgs>
</_AppExtensionCodesignPropertiesToWrite>
</ItemGroup>
<WriteItemsToFile
Condition="'$(IsMacEnabled)' == 'true'"
Items="@(_AppExtensionCodesignPropertiesToWrite)"
ItemName="_AppExtensionCodesignProperties"
File="$(DeviceSpecificOutputPath)codesign.items"
IncludeMetadata="true"
Overwrite="true"
/>
</Target>
<Target Name="_CalculateCodesignAppBundleInputs">
<ItemGroup>
<_CodesignAppBundleInputs Include="$(_AppBundlePath)**\*.*" Exclude="$(_AppCodeSignaturePath)_CodeSignature\CodeResources" />
</ItemGroup>
<PropertyGroup>
<_CodesignDisableTimestamp>False</_CodesignDisableTimestamp>
<_CodesignDisableTimestamp Condition="'$(_SdkIsSimulator)' == 'true' Or '$(_BundlerDebug)' == 'true'">True</_CodesignDisableTimestamp>
<_AppBundleCodesignEntitlements Condition="'$(_PlatformName)' == 'macOS'">$(IntermediateOutputPath)Entitlements.xcent</_AppBundleCodesignEntitlements>
<_AppBundleCodesignEntitlements Condition="'$(_PlatformName)' != 'macOS'">$(_CompiledCodesignEntitlements)</_AppBundleCodesignEntitlements>
<_CodesignAppBundleCondition Condition="'$(_PlatformName)' == 'macOS' And '$(_RequireCodeSigning)'">true</_CodesignAppBundleCondition>
<_CodesignAppBundleCondition Condition="'$(_PlatformName)' != 'macOS' And ('$(_CanOutputAppBundle)' == 'true' And '$(_CodeSigningKey)' != '') And ('$(IsAppExtension)' == 'false' Or '@(_ResolvedAppExtensionReferences)' != '')">true</_CodesignAppBundleCondition>
</PropertyGroup>
<ItemGroup Condition="'$(_CodesignAppBundleCondition)' == 'true'">
<_CodesignItems Include="$(AppBundleDir)">
<CodesignAllocate>$(_CodesignAllocate)</CodesignAllocate>
<CodesignAdditionalFilesToTouch>$(AppBundleDir).dSYM\Contents\Info.plist</CodesignAdditionalFilesToTouch>
<CodesignDeep>$(IsAppExtension)</CodesignDeep>
<CodesignDisableTimestamp>$(_CodesignDisableTimestamp)</CodesignDisableTimestamp>
<CodesignEntitlements>$(_AppBundleCodesignEntitlements)</CodesignEntitlements>
<CodesignExtraArgs>$(CodesignExtraArgs)</CodesignExtraArgs>
<CodesignKeychain>$(CodesignKeychain)</CodesignKeychain>
<CodesignResourceRules>$(_PreparedResourceRules)</CodesignResourceRules>
<CodesignSigningKey>$(_CodeSigningKey)</CodesignSigningKey>
<CodesignStampFile>$(_AppCodeSignaturePath)_CodeSignature\CodeResources</CodesignStampFile>
<!-- CodesignStampPath -->
<CodesignUseHardenedRuntime>$(UseHardenedRuntime)</CodesignUseHardenedRuntime>
<CodesignUseSecureTimestamp>$(UseHardenedRuntime)</CodesignUseSecureTimestamp>
</_CodesignItems>
</ItemGroup>
<!-- Compute some metadata for the items -->
<ItemGroup>
<!-- Compute the relative path of the item in the app bundle -->
<_CodesignItems>
<CodesignRelativeAppBundlePath>$([System.String]::new('%(Identity)').Substring($([MSBuild]::Add($([System.String]::new('%(Identity)').LastIndexOf('.app/')),5))))</CodesignRelativeAppBundlePath>
</_CodesignItems>
<!-- Set CodesignStampPath if it's not set already -->
<_CodesignItems Condition="'%(_CodesignItems.CodesignStampPath)' == ''">
<CodesignStampPath>$(DeviceSpecificIntermediateOutputPath)codesign\</CodesignStampPath>
<IsInputDirectory Condition="Exists('%(_CodesignItems.Identity)') And !$([System.IO.File]::Exists('%(_CodesignItems.Identity)'))">true</IsInputDirectory>
</_CodesignItems>
<!-- Set CodesignStampFile if it's not set already -->
<!-- Don't use a directory as a stamp file, instead use a file inside that directory -->
<!-- This checks if the input is a directory, because we can't check if the stamp location might be (it might not exist yet) -->
<!-- Unfortunately System.IO.Directory.Exists can't be called from MSBuild, so we combine two other methods:
1. The built-in 'Exists' condition returns true if the input is either a file or a directory (and it exists)
2. We can call System.IO.File.Exists, which only returns true if the input is a file (and it exists).
3. So we can determine that the input is a directory, if the built-in 'Exists' return true, but System.IO.File.Exists return false
-->
<_CodesignItems Condition="'%(_CodesignItems.CodesignStampFile)' == ''">
<CodesignStampFile Condition="'%(_CodesignItems.IsInputDirectory)' != 'true'">%(_CodesignItems.CodesignStampPath)\%(_CodesignItems.CodesignRelativeAppBundlePath)</CodesignStampFile>
<CodesignStampFile Condition="'%(_CodesignItems.IsInputDirectory)' == 'true'">%(_CodesignItems.CodesignStampPath)\%(_CodesignItems.CodesignRelativeAppBundlePath)\.directory-stamp</CodesignStampFile>
</_CodesignItems>
</ItemGroup>
</Target>
<!-- sign the app bundle and anything inside that needs signing -->
<!-- This target does not have Inputs/Outputs, because computing what needs signing or not is quite complex:
* If any file inside a directory has been modified, we need to (re)sign
* If any file or directory inside a directory needs to be signed, then the containing directory must be signed as well
This logic is implemented in the Codesign task.
-->
<Target Name="_CodesignAppBundle"
DependsOnTargets="$(_CodesignAppBundleDependsOn)"
>
<Codesign
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
Resources="@(_CodesignItems)"
ToolExe="$(CodesignExe)"
ToolPath="$(CodesignPath)"
>
</Codesign>
</Target>
<!-- LinkMode -->
<PropertyGroup>
<_ComputeLinkModeDependsOn>
@ -2563,8 +2514,9 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<Target Name="_GenerateBundleName" Condition="'$(_CanOutputAppBundle)' == 'true'" DependsOnTargets="_ComputeTargetArchitectures;_ParseBundlerArguments">
<PropertyGroup Condition="'$(AppBundleDir)' == ''">
<AppBundleDir Condition="'$(IsAppDistribution)' != 'true'">$(DeviceSpecificOutputPath)$(_AppBundleName)$(AppBundleExtension)</AppBundleDir>
<AppBundleDir Condition="'$(IsAppDistribution)' == 'true'">$(ArchivePath)\Products\Applications\$(_AppBundleName)$(AppBundleExtension)</AppBundleDir>
<_AppContainerDir Condition="'$(IsAppDistribution)' != 'true'">$(DeviceSpecificOutputPath)</_AppContainerDir>
<_AppContainerDir Condition="'$(IsAppDistribution)' == 'true'">$(ArchivePath)\Products\Applications\</_AppContainerDir>
<AppBundleDir>$(_AppContainerDir)$(_AppBundleName)$(AppBundleExtension)</AppBundleDir>
</PropertyGroup>
<PropertyGroup>
<_AppBundlePath>$(AppBundleDir)\</_AppBundlePath>

Просмотреть файл

@ -523,6 +523,12 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved.
</_AssetPack>
</ItemGroup>
<Delete
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
Files="@(_AssetPack->'%(CodesignStampFile)')"
/>
<!-- Sign assetpacks -->
<Codesign
SessionId="$(BuildSessionId)"

Просмотреть файл

@ -0,0 +1,475 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using NUnit.Framework;
using Xamarin.iOS.Tasks;
using Xamarin.Utils;
#nullable enable
namespace Xamarin.MacDev.Tasks {
[TestFixture]
public class ComputeCodesignItemsTaskTests : TestBase {
[Test]
[TestCase (ApplePlatform.iOS, true)]
[TestCase (ApplePlatform.iOS, false)]
[TestCase (ApplePlatform.TVOS, true)]
[TestCase (ApplePlatform.TVOS, false)]
[TestCase (ApplePlatform.WatchOS, false)]
[TestCase (ApplePlatform.MacOSX, true)]
[TestCase (ApplePlatform.MacOSX, false)]
[TestCase (ApplePlatform.MacCatalyst, true)]
public void Compute (ApplePlatform platform, bool isDotNet)
{
var tmpdir = Cache.CreateTemporaryDirectory ();
var currentDir = Environment.CurrentDirectory;
try {
Environment.CurrentDirectory = tmpdir;
var codesignItems = new List<ITaskItem> ();
var codesignBundle = new List<ITaskItem> ();
string codeSignatureSubdirectory = string.Empty;
switch (platform) {
case ApplePlatform.MacCatalyst:
case ApplePlatform.MacOSX:
codeSignatureSubdirectory = "Contents/";
break;
}
var bundleAppMetadata = new Dictionary<string, string> {
{ "CodesignDisableTimestamp", "true" },
{ "CodesignEntitlements" , "CompiledEntitlements.plist" },
{ "CodesignExtraArgs", "bundle-app-extra-args" },
{ "CodesignKeychain", "bundle-app-keychain" },
{ "CodesignResourceRules", "bundle-app-resource-rules" },
{ "CodesignSigningKey", "bundle-app-signing-key" },
{ "CodesignStampFile", "bundle-app-stamp-file" },
{ "CodesignUseHardenedRuntime", "bundle-app-use-hardened-runtime" },
{ "CodesignUseSecureTimestamp", "bundle-app-use-secure-timestamp" },
{ "RequireCodeSigning", "true" },
};
var bundleAppMetadataNativeLibraries = new Dictionary<string, string> (bundleAppMetadata);
bundleAppMetadataNativeLibraries.Remove ("CodesignEntitlements");
var p1Metadata = new Dictionary<string, string> {
{ "CodesignDisableTimestamp", "true" },
{ "CodesignEntitlements" , "p1.appex-entitlements" },
{ "CodesignExtraArgs", "p1.appex-extra-args" },
{ "CodesignKeychain", "p1.appex-keychain" },
{ "CodesignResourceRules", "p1.appex-resource-rules" },
{ "CodesignSigningKey", "" }, // empty code signing key
{ "CodesignStampFile", "" }, // empty stamp file
{ "CodesignUseHardenedRuntime", "p1.appex-use-hardened-runtime" },
{ "CodesignUseSecureTimestamp", "p1.appex-use-secure-timestamp" },
{ "RequireCodeSigning", "false" }, // don't require code signing
};
var p1MetadataNativeLibraries = new Dictionary<string, string> (p1Metadata);
p1MetadataNativeLibraries ["CodesignSigningKey"] = "-";
p1MetadataNativeLibraries ["CodesignStampFile"] = "_CodeSignature/CodeResources";
p1MetadataNativeLibraries.Remove ("CodesignEntitlements");
var p2Metadata = new Dictionary<string, string> {
{ "CodesignDisableTimestamp", "true" },
{ "CodesignEntitlements" , "p2.appex-entitlements" },
{ "RequireCodeSigning", "true" },
{ "CodesignExtraArgs", "p2.appex-extra-args" },
{ "CodesignKeychain", "p2.appex-keychain" },
{ "CodesignResourceRules", "p2.appex-resource-rules" },
{ "CodesignSigningKey", "p2.appex-signing-key" },
{ "CodesignStampFile", "" }, // empty stamp file
{ "CodesignUseHardenedRuntime", "p2.appex-use-hardened-runtime" },
{ "CodesignUseSecureTimestamp", "p2.appex-use-secure-timestamp" },
};
var p2MetadataNativeLibraries = new Dictionary<string, string> (p2Metadata);
p2MetadataNativeLibraries ["CodesignStampFile"] = "_CodeSignature/CodeResources";
p2MetadataNativeLibraries.Remove ("CodesignEntitlements");
var p3Metadata = new Dictionary<string, string> {
{ "CodesignDisableTimestamp", "true" },
{ "CodesignEntitlements" , "p3.appex-entitlements" },
{ "RequireCodeSigning", "true" },
{ "CodesignExtraArgs", "p3.appex-extra-args" },
{ "CodesignKeychain", "p3.appex-keychain" },
{ "CodesignResourceRules", "p3.appex-resource-rules" },
{ "CodesignSigningKey", "p3.appex-signing-key" },
{ "CodesignStampFile", "" }, // empty stamp file
{ "CodesignUseHardenedRuntime", "p3.appex-use-hardened-runtime" },
{ "CodesignUseSecureTimestamp", "p3.appex-use-secure-timestamp" },
};
var p3MetadataNativeLibraries = new Dictionary<string, string> (p3Metadata);
p3MetadataNativeLibraries ["CodesignStampFile"] = "_CodeSignature/CodeResources";
p3MetadataNativeLibraries.Remove ("CodesignEntitlements");
var w1Metadata = new Dictionary<string, string> {
{ "CodesignDisableTimestamp", "true" },
{ "CodesignEntitlements" , "CompiledEntitlements.plist" },
{ "RequireCodeSigning", "true" },
{ "CodesignExtraArgs", "bundle-app-extra-args" },
{ "CodesignKeychain", "bundle-app-keychain" },
{ "CodesignResourceRules", "bundle-app-resource-rules" },
{ "CodesignSigningKey", "bundle-app-signing-key" },
{ "CodesignStampFile", "" }, // empty stamp file
{ "CodesignUseHardenedRuntime", "bundle-app-use-hardened-runtime" },
{ "CodesignUseSecureTimestamp", "bundle-app-use-secure-timestamp" },
};
var w1MetadataNativeLibraries = new Dictionary<string, string> (w1Metadata);
w1MetadataNativeLibraries.Remove ("CodesignEntitlements");
var wp1Metadata = new Dictionary<string, string> {
{ "CodesignDisableTimestamp", "true" },
{ "CodesignEntitlements" , "wp1.appex-entitlements" },
{ "RequireCodeSigning", "true" },
{ "CodesignExtraArgs", "wp1.appex-extra-args" },
{ "CodesignKeychain", "wp1.appex-keychain" },
{ "CodesignResourceRules", "wp1.appex-resource-rules" },
{ "CodesignSigningKey", "" }, // empty code signing key
{ "CodesignStampFile", "" }, // empty stamp file
{ "CodesignUseHardenedRuntime", "wp1.appex-use-hardened-runtime" },
{ "CodesignUseSecureTimestamp", "wp1.appex-use-secure-timestamp" },
};
var wp1MetadataNativeLibraries = new Dictionary<string, string> (wp1Metadata);
wp1MetadataNativeLibraries ["CodesignSigningKey"] = "-";
wp1MetadataNativeLibraries ["CodesignStampFile"] = "_CodeSignature/CodeResources";
wp1MetadataNativeLibraries.Remove ("CodesignEntitlements");
var wp2Metadata = new Dictionary<string, string> {
{ "CodesignDisableTimestamp", "true" },
{ "CodesignEntitlements" , "wp2.appex-entitlements" },
{ "RequireCodeSigning", "true" },
{ "CodesignExtraArgs", "wp2.appex-extra-args" },
{ "CodesignKeychain", "wp2.appex-keychain" },
{ "CodesignResourceRules", "wp2.appex-resource-rules" },
{ "CodesignSigningKey", "wp2.appex-signing-key" },
{ "CodesignStampFile", "" }, // empty stamp file
{ "CodesignUseHardenedRuntime", "wp2.appex-use-hardened-runtime" },
{ "CodesignUseSecureTimestamp", "wp2.appex-use-secure-timestamp" },
};
var wp2MetadataNativeLibraries = new Dictionary<string, string> (wp2Metadata);
wp2MetadataNativeLibraries ["CodesignStampFile"] = "_CodeSignature/CodeResources";
wp2MetadataNativeLibraries.Remove ("CodesignEntitlements");
var wp3Metadata = new Dictionary<string, string> {
{ "CodesignDisableTimestamp", "true" },
{ "CodesignEntitlements" , "wp3.appex-entitlements" },
{ "RequireCodeSigning", "true" },
{ "CodesignExtraArgs", "wp3.appex-extra-args" },
{ "CodesignKeychain", "wp3.appex-keychain" },
{ "CodesignResourceRules", "wp3.appex-resource-rules" },
{ "CodesignSigningKey", "wp3.appex-signing-key" },
{ "CodesignStampFile", "" }, // empty stamp file
{ "CodesignUseHardenedRuntime", "wp3.appex-use-hardened-runtime" },
{ "CodesignUseSecureTimestamp", "wp3.appex-use-secure-timestamp" },
};
var wp3MetadataNativeLibraries = new Dictionary<string, string> (wp3Metadata);
wp3MetadataNativeLibraries ["CodesignStampFile"] = "_CodeSignature/CodeResources";
wp3MetadataNativeLibraries.Remove ("CodesignEntitlements");
var createDumpMetadata = new Dictionary<string, string> {
{ "CodesignDisableTimestamp", "true" },
{ "CodesignEntitlements" , "createdump-entitlements" },
{ "RequireCodeSigning", "true" },
{ "CodesignExtraArgs", "createdump-extra-args" },
{ "CodesignKeychain", "createdump-keychain" },
{ "CodesignResourceRules", "createdump-resource-rules" },
{ "CodesignSigningKey", "createdump-signing-key" },
{ "CodesignStampFile", "createdump-stamp-file" },
{ "CodesignUseHardenedRuntime", "createdump-use-hardened-runtime" },
{ "CodesignUseSecureTimestamp", "createdump-use-secure-timestamp" },
};
codesignItems = new List<ITaskItem> {
new TaskItem ("Bundle.app/Contents/MonoBundle/createdump", createDumpMetadata),
};
codesignBundle = new List<ITaskItem> {
new TaskItem ("Bundle.app", bundleAppMetadata),
new TaskItem ("Bundle.app/PlugIns/P1.appex", p1Metadata),
new TaskItem ("Bundle.app/PlugIns/P1.appex/PlugIns/P2.appex", p2Metadata),
new TaskItem ("Bundle.app/PlugIns/P1.appex/PlugIns/P2.appex/PlugIns/P3.appex", p3Metadata),
new TaskItem ("Bundle.app/Watch/W1.app", w1Metadata),
new TaskItem ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex", wp1Metadata),
new TaskItem ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex", wp2Metadata),
new TaskItem ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex", wp3Metadata),
};
var infos = new CodesignInfo [] {
new CodesignInfo ("Bundle.app", Platforms.All, bundleAppMetadata.Set ("CodesignAdditionalFilesToTouch", "Bundle.app.dSYM/Contents/Info.plist")),
new CodesignInfo ("Bundle.app/a.dylib", Platforms.Mobile, bundleAppMetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/a.dylib")),
new CodesignInfo ("Bundle.app/Contents/b.dylib", Platforms.All, bundleAppMetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Contents/b.dylib")),
new CodesignInfo ("Bundle.app/Contents/MonoBundle/c.dylib", Platforms.All, bundleAppMetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Contents/MonoBundle/c.dylib")),
new CodesignInfo ("Bundle.app/Contents/MonoBundle/SubDir/d.dylib", Platforms.All, bundleAppMetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Contents/MonoBundle/SubDir/d.dylib")),
new CodesignInfo ("Bundle.app/M1.metallib", Platforms.Mobile, bundleAppMetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/M1.metallib")),
new CodesignInfo ("Bundle.app/Resources/M2.metallib", Platforms.Mobile, bundleAppMetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Resources/M2.metallib")),
new CodesignInfo ("Bundle.app/Contents/Resources/M3.metallib", Platforms.All, bundleAppMetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Contents/Resources/M3.metallib")),
new CodesignInfo ("Bundle.app/Contents/Resources/SubDir/M4.metallib", Platforms.All, bundleAppMetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Contents/Resources/SubDir/M4.metallib")),
new CodesignInfo (
"Bundle.app/PlugIns/P1.appex",
Platforms.None,
p1Metadata.
Set ("CodesignStampFile", $"Bundle.app/PlugIns/P1.appex/PlugIns/P2.appex/{codeSignatureSubdirectory}_CodeSignature/CodeResources")
),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/P1a.dylib", Platforms.Mobile, p1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/P1a.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/Contents/P1b.dylib", Platforms.All, p1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/Contents/P1b.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/Contents/MonoBundle/P1c.dylib", Platforms.All, p1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/Contents/MonoBundle/P1c.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/Contents/MonoBundle/SubDir/P1d.dylib", Platforms.All, p1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/Contents/MonoBundle/SubDir/P1d.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/PM1.metallib", Platforms.Mobile, p1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/PM1.metallib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/Resources/PM2.metallib", Platforms.Mobile, p1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/Resources/PM2.metallib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/Contents/Resources/PM3.metallib", Platforms.All, p1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/Contents/Resources/PM3.metallib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/Contents/Resources/SubDir/PM4.metallib", Platforms.All, p1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/Contents/Resources/SubDir/PM4.metallib")),
new CodesignInfo (
"Bundle.app/PlugIns/P1.appex/plugins/P2.appex",
Platforms.All,
p2Metadata.
Set ("CodesignStampFile", $"Bundle.app/PlugIns/P1.appex/PlugIns/P2.appex/{codeSignatureSubdirectory}_CodeSignature/CodeResources").
Set ("CodesignAdditionalFilesToTouch", "P2.appex.dSYM/Contents/Info.plist")
),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/P2a.dylib", Platforms.Mobile, p2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/P2a.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/P2b.dylib", Platforms.All, p2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/P2b.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/MonoBundle/P2c.dylib", Platforms.All, p2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/MonoBundle/P2c.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/MonoBundle/SubDir/P2d.dylib", Platforms.All, p2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/MonoBundle/SubDir/P2d.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/P2M1.metallib", Platforms.Mobile, p2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/P2M1.metallib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Resources/P2M2.metallib", Platforms.Mobile, p2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Resources/P2M2.metallib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/Resources/P2M3.metallib", Platforms.All, p2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/Resources/P2M3.metallib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/Resources/SubDir/P2M4.metallib", Platforms.All, p2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/Contents/Resources/SubDir/P2M4.metallib")),
new CodesignInfo (
"Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex",
Platforms.All,
p3Metadata.
Set ("CodesignStampFile", $"Bundle.app/PlugIns/P1.appex/PlugIns/P2.appex/PlugIns/P3.appex/{codeSignatureSubdirectory}_CodeSignature/CodeResources").
Set ("CodesignAdditionalFilesToTouch", "P3.appex.dSYM/Contents/Info.plist")
),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/P3a.dylib", Platforms.Mobile, p3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/P3a.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/P3b.dylib", Platforms.All, p3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/P3b.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/MonoBundle/P3c.dylib", Platforms.All, p3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/MonoBundle/P3c.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/MonoBundle/SubDir/P3d.dylib", Platforms.All, p3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/MonoBundle/SubDir/P3d.dylib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/P3M1.metallib", Platforms.Mobile, p3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/P3M1.metallib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Resources/P3M2.metallib", Platforms.Mobile, p3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Resources/P3M2.metallib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/Resources/P3M3.metallib", Platforms.All, p3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/Resources/P3M3.metallib")),
new CodesignInfo ("Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/Resources/SubDir/P3M4.metallib", Platforms.All, p3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/PlugIns/P1.appex/plugins/P2.appex/PlugIns/P3.appex/Contents/Resources/SubDir/P3M4.metallib")),
new CodesignInfo (
"Bundle.app/Watch/W1.app",
Platforms.All,
w1Metadata.
Set ("CodesignStampFile", $"Bundle.app/Watch/W1.app/{codeSignatureSubdirectory}_CodeSignature/CodeResources").
Set ("CodesignAdditionalFilesToTouch", "W1.app.dSYM/Contents/Info.plist")
),
new CodesignInfo ("Bundle.app/Watch/W1.app/Contents/b.dylib", Platforms.All, w1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/Contents/b.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/Contents/MonoBundle/c.dylib", Platforms.All, w1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/Contents/MonoBundle/c.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/Contents/MonoBundle/SubDir/d.dylib", Platforms.All, w1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/Contents/MonoBundle/SubDir/d.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/W1M1.metallib", Platforms.Mobile, w1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/W1M1.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/Resources/W1M2.metallib", Platforms.Mobile, w1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/Resources/W1M2.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/Contents/Resources/W1M3.metallib", Platforms.All, w1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/Contents/Resources/W1M3.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/Contents/Resources/SubDir/W1M4.metallib", Platforms.All, w1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/Contents/Resources/SubDir/W1M4.metallib")),
new CodesignInfo (
"Bundle.app/Watch/W1.app/PlugIns/WP1.appex",
Platforms.All,
wp1Metadata.
Set ("CodesignStampFile", $"Bundle.app/Watch/W1.app/PlugIns/WP1.appex/{codeSignatureSubdirectory}_CodeSignature/CodeResources").
Set ("CodesignAdditionalFilesToTouch", "WP1.appex.dSYM/Contents/Info.plist")
),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/W1a.dylib", Platforms.Mobile, wp1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/W1a.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/W1b.dylib", Platforms.All, wp1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/W1b.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/MonoBundle/W1c.dylib", Platforms.All, wp1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/MonoBundle/W1c.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/MonoBundle/SubDir/W1d.dylib", Platforms.All, wp1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/MonoBundle/SubDir/W1d.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/W1M1.metallib", Platforms.Mobile, wp1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/W1M1.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Resources/W1M2.metallib", Platforms.Mobile, wp1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Resources/W1M2.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/Resources/W1M3.metallib", Platforms.All, wp1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/Resources/W1M3.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/Resources/SubDir/W1M4.metallib", Platforms.All, wp1MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/Contents/Resources/SubDir/W1M4.metallib")),
new CodesignInfo (
"Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex",
Platforms.All,
wp2Metadata.
Set ("CodesignStampFile", $"Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/{codeSignatureSubdirectory}_CodeSignature/CodeResources").
Set ("CodesignAdditionalFilesToTouch", "WP2.appex.dSYM/Contents/Info.plist")
),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/W2a.dylib", Platforms.Mobile, wp2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/W2a.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/W2b.dylib", Platforms.All, wp2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/W2b.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/MonoBundle/W2c.dylib", Platforms.All, wp2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/MonoBundle/W2c.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/MonoBundle/SubDir/W2c.dylib", Platforms.All, wp2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/MonoBundle/SubDir/W2c.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/W2M1.metallib", Platforms.Mobile, wp2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/W2M1.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Resources/W2M2.metallib", Platforms.Mobile, wp2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Resources/W2M2.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/Resources/W2M3.metallib", Platforms.All, wp2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/Resources/W2M3.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/Resources/SubDir/W2M4.metallib", Platforms.All, wp2MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/Contents/Resources/SubDir/W2M4.metallib")),
new CodesignInfo (
"Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex",
Platforms.All,
wp3Metadata.
Set ("CodesignStampFile", $"Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/{codeSignatureSubdirectory}_CodeSignature/CodeResources").
Set ("CodesignAdditionalFilesToTouch", "WP3.appex.dSYM/Contents/Info.plist")
),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/W3a.dylib", Platforms.Mobile, wp3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/W3a.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/W3b.dylib", Platforms.All, wp3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/W3b.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/MonoBundle/W3c.dylib", Platforms.All, wp3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/MonoBundle/W3c.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/MonoBundle/SubDir/W3c.dylib", Platforms.All, wp3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/MonoBundle/SubDir/W3c.dylib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/W3M1.metallib", Platforms.Mobile, wp3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/W3M1.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Resources/W3M2.metallib", Platforms.Mobile, wp3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Resources/W3M2.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/Resources/W3M3.metallib", Platforms.All, wp3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/Resources/W3M3.metallib")),
new CodesignInfo ("Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/Resources/SubDir/W3M4.metallib", Platforms.All, wp3MetadataNativeLibraries.Set ("CodesignStampFile", "codesign-stamp-path/Bundle.app/Watch/W1.app/PlugIns/WP1.appex/PlugIns/WP2.appex/PlugIns/WP3.appex/Contents/Resources/SubDir/W3M4.metallib")),
new CodesignInfo ("Bundle.app/Contents/MonoBundle/createdump", Platforms.All, createDumpMetadata),
};
var allFiles = infos.Select (v => v.ItemSpec).ToArray ();
Touch (tmpdir, allFiles);
var task = CreateTask<ComputeCodesignItems> ();
task.AppBundleDir = "Bundle.app";
task.CodesignBundle = codesignBundle.ToArray ();
task.CodesignItems = codesignItems.ToArray ();
task.CodesignStampPath = "codesign-stamp-path/";
task.TargetFrameworkMoniker = TargetFramework.GetTargetFramework (platform, isDotNet).ToString ();
Assert.IsTrue (task.Execute (), "Execute");
var outputCodesignItems = task.OutputCodesignItems;
Assert.That (outputCodesignItems.Select (v => v.ItemSpec), Is.Unique, "Uniqueness");
var failures = new List<string> ();
var itemsFound = new List<ITaskItem> ();
foreach (var info in infos) {
var item = outputCodesignItems.SingleOrDefault (v => string.Equals (v.ItemSpec, info.ItemSpec, StringComparison.OrdinalIgnoreCase));
info.CodesignItem = item;
if (IsPlatform (info.SignedOn, platform)) {
if (item is null) {
failures.Add ($"Expected '{info.ItemSpec}' to be signed.");
continue;
}
} else {
if (item is not null) {
failures.Add ($"Did not expect '{info.ItemSpec}' to be signed.");
continue;
}
}
if (item is null)
continue;
itemsFound.Add (item);
foreach (var kvp in info.Metadata) {
var metadata = item.GetMetadata (kvp.Key);
if (metadata == string.Empty && kvp.Value != string.Empty) {
failures.Add ($"Item '{info.ItemSpec}': Expected metadata '{kvp.Key}' not found (with value '{kvp.Value}').");
} else if (!string.Equals (metadata, kvp.Value)) {
failures.Add ($"Item '{info.ItemSpec}': Expected value '{kvp.Value}' for metadata '{kvp.Key}', but got '{metadata}' instead.\nExpected: {kvp.Value}\nActual: {metadata}");
}
}
var customMetadata = item.CopyCustomMetadata ();
var unexpectedMetadata = customMetadata.Keys.ToHashSet ();
unexpectedMetadata.ExceptWith (info.Metadata.Keys);
unexpectedMetadata.Remove ("OriginalItemSpec");
foreach (var unexpected in unexpectedMetadata) {
if (string.IsNullOrEmpty (customMetadata [unexpected]))
continue;
failures.Add ($"Item '{info.ItemSpec}': Unexpected metadata '{unexpected}' with value '{customMetadata [unexpected]}'.");
}
}
var itemsNotFound = outputCodesignItems.Where (v => !itemsFound.Contains (v)).ToArray ();
foreach (var itemNotFound in itemsNotFound) {
failures.Add ($"Did not expect '{itemNotFound.ItemSpec}' to be signed.");
}
if (failures.Count > 0) {
Console.WriteLine ($"{failures.Count} failures");
foreach (var f in failures)
Console.WriteLine (f);
Console.WriteLine ($"{failures.Count} failures");
}
Assert.That (failures, Is.Empty, "Failures");
} finally {
Environment.CurrentDirectory = currentDir;
}
}
bool IsPlatform (Platforms platforms, ApplePlatform platform)
{
switch (platform) {
case ApplePlatform.iOS:
return (platforms & Platforms.iOS) == Platforms.iOS;
case ApplePlatform.TVOS:
return (platforms & Platforms.tvOS) == Platforms.tvOS;
case ApplePlatform.MacOSX:
return (platforms & Platforms.macOS) == Platforms.macOS;
case ApplePlatform.WatchOS:
return (platforms & Platforms.watchOS) == Platforms.watchOS;
case ApplePlatform.MacCatalyst:
return (platforms & Platforms.MacCatalyst) == Platforms.MacCatalyst;
default:
throw new NotImplementedException ();
}
}
void Touch (string root, params string [] files)
{
foreach (var f in files) {
var file = Path.Combine (root, f);
if (file.EndsWith (".appex", StringComparison.OrdinalIgnoreCase) || file.EndsWith (".app", StringComparison.OrdinalIgnoreCase)) {
Directory.CreateDirectory (f);
} else {
Directory.CreateDirectory (Path.GetDirectoryName (file));
File.WriteAllText (file, string.Empty);
}
}
}
class CodesignInfo {
public string ItemSpec;
public Platforms SignedOn;
public Dictionary<string, string> Metadata;
public ITaskItem? CodesignItem;
public CodesignInfo (string item, Platforms signedOn, Dictionary<string, string>? metadata = null)
{
ItemSpec = item;
SignedOn = signedOn;
Metadata = metadata ?? new Dictionary<string, string> ();
}
}
// As opposed to ApplePlatform, this enum is a bitfield, and can represent multiple platforms in a single value.
[Flags]
enum Platforms {
None = 0,
iOS = 1,
tvOS = 2,
watchOS = 4,
macOS = 8,
MacCatalyst = 16,
Mobile = iOS | tvOS | watchOS,
Desktop = macOS | MacCatalyst,
All = Mobile | Desktop,
}
}
public static class Dictionary_Extensions {
public static Dictionary<string, string> Set (this Dictionary<string, string> self, string key, string value)
{
var rv = new Dictionary<string, string> (self);
rv [key] = value;
return rv;
}
}
public static class ITaskItem_Extensions {
public static Dictionary<string, string> CopyCustomMetadata (this ITaskItem self)
{
var rv = new Dictionary<string, string> ();
foreach (DictionaryEntry de in self.CloneCustomMetadata ()) {
rv [(string) de.Key] = (string) de.Value;
}
return rv;
}
}
}

Просмотреть файл

@ -17,6 +17,20 @@ namespace Xamarin.Utils
return (((uint) c - 'a') <= ((uint) 'z' - 'a')) ? (char) (c - 0x20) : c;
}
public static string EnsureTrailingSlash (this string path)
{
if (path is null)
return null;
if (path.Length == 0)
return Path.DirectorySeparatorChar.ToString ();
if (path [path.Length - 1] != Path.DirectorySeparatorChar)
path += Path.DirectorySeparatorChar;
return path;
}
[DllImport ("/usr/lib/libc.dylib")]
static extern IntPtr realpath (string path, IntPtr buffer);