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

[msbuild] Validate entitlements in CompileEntitlements. #21771

Merged
merged 5 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 4 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
14 changes: 14 additions & 0 deletions docs/building-apps/build-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,20 @@ Whether the native http handler should be the default http handler or not.

Default: true for all platforms except macOS.

## ValidateEntitlements

Choose whether entitlements the app requests should be validated.

Valid values for this property:

* `disable`: Validation is disabled.
* `warn`: Any validation failures are shown as warnings.
* `error`: Any validation failures are shown as errors. This is the default.

The validation process may not validate every entitlement, nor is it guaranteed to not be overeager.

If the validation fails for entitlements that actually work, please file a new issue.

## XamMacResourcePrefix

The directory where resources are stored (this prefix will be removed when copying resources to the app bundle).
Expand Down
30 changes: 30 additions & 0 deletions msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1662,4 +1662,34 @@
<data name="E7136" xml:space="preserve">
<value>Unknown resource type: {1}.</value>
</data>

<data name="E7137" xml:space="preserve">
<value>The app requests the entitlement '{0}' with the value '{1}', but the provisioning profile '{2}' grants it for the value '{3}'.</value>
<comment>
This may be either a warning or an error, depending on build configuration.
</comment>
</data>

<data name="E7138" xml:space="preserve">
<value>Invalid value '{0}' for the 'ValidateEntitlements' property. Valid values are: 'disable', 'warn' or 'error'.</value>
<comment>
The following are literal names and should not be translated: ValidateEntitlements, disable, warn, error
</comment>
</data>

<data name="E7139" xml:space="preserve">
<value>The app requests the entitlement '{0}', but no provisioning profile has been specified. Please specify the name of the provisioning profile to use with the 'CodesignProvision' property in the project file.</value>
<comment>
This may be either a warning or an error, depending on build configuration.
The following are literal names and should not be translated: CodesignProvision
</comment>
</data>

<data name="E7140" xml:space="preserve">
<value>The app requests the entitlement '{0}', but the provisioning profile '{1}' does not contain this entitlement.</value>
<comment>
This may be either a warning or an error, depending on build configuration.
</comment>
</data>

</root>
6 changes: 4 additions & 2 deletions msbuild/Xamarin.MacDev.Tasks/LoggingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

#nullable enable

namespace Xamarin.MacDev.Tasks {
public static class LoggingExtensions {
const MessageImportance TaskPropertyImportance = MessageImportance.Normal;
Expand Down Expand Up @@ -79,12 +81,12 @@ public static void LogTaskProperty (this TaskLoggingHelper log, string propertyN
/// <param name="errorCode">In the 7xxx range for MSBuild error.</param>
/// <param name="message">The error's message to be displayed in the error pad.</param>
/// <param name="fileName">Path to the known guilty file or null.</param>
public static void LogError (this TaskLoggingHelper log, int errorCode, string? fileName, string message, params object [] args)
public static void LogError (this TaskLoggingHelper log, int errorCode, string? fileName, string message, params object? [] args)
{
log.LogError (null, $"{ErrorPrefix}{errorCode}", null, fileName ?? "MSBuild", 0, 0, 0, 0, message, args);
}

public static void LogWarning (this TaskLoggingHelper log, int errorCode, string? fileName, string message, params object [] args)
public static void LogWarning (this TaskLoggingHelper log, int errorCode, string? fileName, string message, params object? [] args)
{
log.LogWarning (null, $"{ErrorPrefix}{errorCode}", null, fileName ?? "MSBuild", 0, 0, 0, 0, message, args);
}
Expand Down
61 changes: 61 additions & 0 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public class CompileEntitlements : XamarinTask, ITaskCallback, ICancelableTask {
[Output]
public ITaskItem? EntitlementsInSignature { get; set; }

public string ValidateEntitlements { get; set; } = string.Empty;
#endregion

protected string ApplicationIdentifierKey {
Expand Down Expand Up @@ -510,6 +511,9 @@ public override bool Execute ()
}

compiled = GetCompiledEntitlements (profile, template);

ValidateAppEntitlements (profile, compiled);

archived = GetArchivedExpandedEntitlements (template, compiled);

try {
Expand Down Expand Up @@ -568,6 +572,63 @@ bool SaveArchivedExpandedEntitlements (PDictionary archived)
return true;
}

void ValidateAppEntitlements (MobileProvision? profile, PDictionary requestedEntitlements)
{
var onlyWarn = false;
switch (ValidateEntitlements?.ToLowerInvariant ()) {
case "disable":
return;
case "warn":
onlyWarn = true;
break;
case null: // default to 'error'
case "":
case "error":
onlyWarn = false;
break;
default:
Log.LogError (7138, null, MSBStrings.E7138, ValidateEntitlements); // Invalid value '{0}' for the 'ValidateEntitlements' property. Valid values are: 'disable', 'warn' or 'error'.
return;
}

if (requestedEntitlements is null || requestedEntitlements.Count == 0) {
// Everything is OK if the app doesn't request any entitlements.
return;
}

var provisioningEntitlements = profile?.Entitlements;
var provisioningProfileName = profile?.Name;
foreach (var kvp in requestedEntitlements) {
var key = kvp.Key;
switch (key) {
case "aps-environment":
var requestedApsEnvironment = (kvp.Value as PString)?.Value;
if (profile is null) {
LogEntitlementValidationFailure (onlyWarn, 7139, MSBStrings.E7139, key); // "The app requests the entitlement '{0}', but no provisioning profile has been specified. Please specify the name of the provisioning profile to use with the 'CodesignProvision' property in the project file.
} else if (provisioningEntitlements is null || !provisioningEntitlements.TryGetValue<PString> (key, out var provisioningApsEnvironment)) {
LogEntitlementValidationFailure (onlyWarn, 7140, MSBStrings.E7140, key, provisioningProfileName); // The app requests the entitlement '{0}', but the provisioning profile '{1}' does not contain this entitlement.
} else if (requestedApsEnvironment != provisioningApsEnvironment.Value) {
LogEntitlementValidationFailure (onlyWarn, 7137, MSBStrings.E7137, key, requestedApsEnvironment, provisioningProfileName, provisioningApsEnvironment.Value); // The app requests the entitlement '{0}' with the value '{1}', but the provisioning profile '{2}' grants it for the value '{3}'."
} else {
Log.LogMessage (MessageImportance.Low, $"The app requests the entitlement '{key}' with the value '{requestedApsEnvironment}', which the provisioning profile '{provisioningProfileName}' grants.");
}
break;
default:
Log.LogMessage (MessageImportance.Low, $"The app requests entitlement '{key}', but no validation has been implemented for this entitlement. Assuming everything is OK.");
break;
}
}
}

void LogEntitlementValidationFailure (bool onlyWarn, int code, string message, params object? [] args)
{
if (onlyWarn) {
Log.LogWarning (code, Entitlements, message, args);
} else {
Log.LogError (code, Entitlements, message, args);
}
}

public bool ShouldCopyToBuildServer (ITaskItem item) => true;

public bool ShouldCreateOutputFile (ITaskItem item)
Expand Down
17 changes: 15 additions & 2 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

namespace Xamarin.MacDev.Tasks {
public class DetectSigningIdentity : XamarinTask, ITaskCallback, ICancelableTask {
CodeSignIdentity detectedIdentity;

const string AutomaticProvision = "Automatic";
const string AutomaticAdHocProvision = "Automatic:AdHoc";
const string AutomaticAppStoreProvision = "Automatic:AppStore";
Expand Down Expand Up @@ -284,8 +286,17 @@ void ReportDetectedCodesignInfo ()
Log.LogMessage (MessageImportance.High, MSBStrings.M0125);
if (codesignCommonName is not null || !string.IsNullOrEmpty (DetectedCodeSigningKey))
Log.LogMessage (MessageImportance.High, " Code Signing Key: \"{0}\" ({1})", codesignCommonName, DetectedCodeSigningKey);
if (provisioningProfileName is not null)
Log.LogMessage (MessageImportance.High, " Provisioning Profile: \"{0}\" ({1})", provisioningProfileName, DetectedProvisioningProfile);
if (provisioningProfileName is not null) {
var profileEntitlements = detectedIdentity.Profile?.Entitlements;
var entitlements = profileEntitlements?.ToXml ().TrimEnd ().Replace ("\n", "\n ");
if (string.IsNullOrEmpty (entitlements)) {
Log.LogMessage (MessageImportance.High, " Provisioning Profile: \"{0}\" ({1}) - no entitlements", provisioningProfileName, DetectedProvisioningProfile);
} else {
Log.LogMessage (MessageImportance.High, " Provisioning Profile: \"{0}\" ({1}) - {2} entitlements", provisioningProfileName, DetectedProvisioningProfile, profileEntitlements?.Count ?? 0);
Log.LogMessage (MessageImportance.Low, $" Entitlements granted by the provisioning profile:");
Log.LogMessage (MessageImportance.Low, $" {entitlements}");
}
}
Log.LogMessage (MessageImportance.High, " Bundle Id: {0}", BundleIdentifier);
Log.LogMessage (MessageImportance.High, " App Id: {0}", DetectedAppId);
}
Expand Down Expand Up @@ -547,6 +558,8 @@ bool ExecuteImpl ()
IList<X509Certificate2> certs;
List<CodeSignIdentity> pairs;

detectedIdentity = identity;

switch (SdkPlatform) {
case "AppleTVSimulator":
case "AppleTVOS":
Expand Down
1 change: 1 addition & 0 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
SdkVersion="$(_SdkVersion)"
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
Debug="$(_BundlerDebug)"
ValidateEntitlements="$(ValidateEntitlements)"
>

<!-- $(_CompiledEntitlements) will be passed to the native compiler, it's used to embed the entitlements in the executable -->
Expand Down
Binary file not shown.
Loading
Loading