How to disable sandbox for Xcode UI tests - xcode

For my macOS desktop application's UI test target, I need to be able to run command line tools (specifically git) to verify some application actions, but I get an error that it cannot be run in the app sandbox.
I never explicitly enabled sandboxing for either my app or for the test target, so I'm having trouble figuring out how to turn it off. There is no entitlements file, and I can't find any target settings that seem to relate to sandboxing.
So is it possible to disable sandboxing for a UI test target? I know workarounds could include copying git into the bundle, or having the user explicitly select the tool, but neither of those seems really desirable.
Update: I tried copying git into the test bundle to run from there, but still got the same error.
Update 2: You can turn off sandboxing for the test bundle, but the test runner which Xcode builds automatically is still sandboxed (and unable to load an unsigned bundle), and AFAICT there is no way to change how the runner is built. Am I wrong?

Create .entitlements file with
<key>com.apple.security.app-sandbox</key>
<false/>
and specify CODE_SIGN_ENTITLEMENTS for your UI Tests bundle(via xcconfig or Build Settings -> Signing). Xcode will use value for this entitlement for test runner application.

The fix that worked for me was to copy git into the bundle, making sure that it's code signed during the build. Then it can be run from the sandboxed test runner.
The catch is that the binary at /usr/bin/git is not the real git tool, it's a placeholder that forwards to xcrun which finds your active Xcode installation and runs the copy of git inside that app bundle, and you can't do any of that inside the sandbox. So you have to copy it directly out of Xcode.
Like this:
Add git from Xcode by navigating to Xcode.app/Contents/Developer/usr/bin/git and setting the Location popup to "Relative to Developer Directory"
Add a Copy Files build phase to your UI Test target to copy git into the Executables directory (if you put it elsewhere it won't get code signed as an executable)
Make sure "Code Sign on Copy" is checked in that build phase (it's the default)
At runtime, find git using Bundle(identifier: YourTestBundleID).url(forAuxiliaryExecutable: "git")

Related

Failed to launch macOS app built in Xcode

I've built an App in Xcode in release mode. Is signed with valid Developer ID certificate. And the app launches fine on some MacBooks.
But on another launch fails with error
The application %name% can't be opened.
Then I try to launch it from terminal with open command it says
LSOpenURLsWithRole() failed with error -54 for the file /Applications/Gaetano Lunches.app.
And then I try to launch directly the binary file from package contents
it says
-bash: /Applications/Gaetano Lunches.app/Contents/MacOS/Gaetano Lunches: Operation not permitted
On all MacBooks app installation from Anywhere is allowed. spctl-master is disabled. Permissions for files are correct. But the app cannot be launched.
I don't know how you are building your app, but if LSOpenURLsWithRole is returning permError = -54, this means you have a permission error on opening a file. This can mean a lot of things, but building an app in release mode is no longer what Apple recommends for you to do. Apple prefers that you use Archive and then you export the app in Organizer to be used by your users. By using this work flow, normally you can do everything using the Xcode defaults for building an app. If you don't, then you need to be more careful with the settings you choose for building in release mode.
For a quick and dirty approach, I would try the following:
1) Open the terminal
2) Type: chmod +x "/Applications/Gaetano Lunches.app/Contents/MacOS/Gaetano Lunches"
3) Try to launch your app and see if it helps. If it helps, there is something messed up with your build settings, which is failing to change the file permissions somewhere for your executable to have the right permissions to be launched.
Another thing you could try is see whether your app was blacklisted by Gatekeeper, because somehow it determined your app is doing suspicious things on your own system. If that is the case, then you can try this to see what gatekeeper is assessing:
spctl -a "/Applications/Gaetano Lunches.app"
If for some weird reason you app is being blacklisted by Gatekeeper, you can always add your app manually and whitelist it for Gatekeeper:
spctl --add "/Applications/Gaetano Lunches.app"
If all fails, you can try to reset the whole database, but you will need super user access:
sudo spctl --reset-default
However, I think these are just quick fixes, and if you keep needing this is because your build settings in Xcode must be adjusted. More on that, if any of these solutions work. Let me know about that.

xcodebuild does not install into applications folder

I have an XCode project with two executable targets, which I use for my own work (that is, I don't sell or publish the applications, but they are still important to me), which depends on one external project. Until now, it has been unproblematic to build the Application(s) and install into the /Applications folder. What I did, was go into the command line and type:
sudo xcodebuild -scheme Trainer install
This would install the target Trainer into the Applications folder, and the application could be run from there. If I tried to specify the target using -target Trainer instead, it would not work, as it would not find dependencies in the external project. Anyway, since last time it worked, two things have happened:
I have upgraded to OS X 10.11
I have upgraded XCode to Version 7.1.1 (7B1005)
Whatever the reason, xcodebuild does no longer install the built product into the /Applications folder. The last lines from the build log, when building with xcodebuild now are:
Touch /var/root/Library/Developer/Xcode/DerivedData/SoundSample-bvsqlgnuhfmtjkgkhevztdzbjbie/Build/Intermediates/ArchiveIntermediates/Trainer/BuildProductsPath/Release/Trainer.app.dSYM
cd /Users/pbholmen/Projects/SoundSample
/usr/bin/touch -c /var/root/Library/Developer/Xcode/DerivedData/SoundSample-bvsqlgnuhfmtjkgkhevztdzbjbie/Build/Intermediates/ArchiveIntermediates/Trainer/BuildProductsPath/Release/Trainer.app.dSYM
RegisterWithLaunchServices /var/root/Library/Developer/Xcode/DerivedData/SoundSample-bvsqlgnuhfmtjkgkhevztdzbjbie/Build/Intermediates/ArchiveIntermediates/Trainer/InstallationBuildProductsLocation/Applications/Trainer.app
cd /Users/pbholmen/Projects/SoundSample
builtin-lsRegisterURL /var/root/Library/Developer/Xcode/DerivedData/SoundSample-bvsqlgnuhfmtjkgkhevztdzbjbie/Build/Intermediates/ArchiveIntermediates/Trainer/InstallationBuildProductsLocation/Applications/Trainer.app
** INSTALL SUCCEEDED **
I have tried to simply copy the Trainer.app that it builds into the /Applications folder, but if I double-click on it, it just won't run. Of course, the Application works when built and run from within XCode, both with the "Debug" and "Release" configuration.
Back when it did work, this would be the last lines of the build log (in Terminal):
Touch build/Release/Trainer.app.dSYM
cd /Users/pbholmen/Projects/SoundSample
/usr/bin/touch -c /Users/pbholmen/Projects/SoundSample/build/Release/SoundSample.app.dSYM
RegisterWithLaunchServices /Applications/Trainer.app
cd /Users/pbholmen/Projects/SoundSample
builtin-lsRegisterURL /Applications/Trainer.app
** INSTALL SUCCEEDED **
If I try to go into the build log from within XCode, find where it puts the builds, and maneuver into that location in Finder and start the application from outside of XCode, that doesn't work either.
Here you can see my Deployment build settings for the target:
Build settings
Under "Deployment location" I have tried both "YES" and "NO", and under "OS X Deployment target" I have tried both "OS X 10.10" and "OS X 10.11". And all four combinations of the two.
After hours of twiddling, I finally figured out the answer. First off, the command
sudo xcodebuild -scheme Trainer install
is wrong. It was a workaround, because I couldn't get XCode to manage my external dependencies from the command line, even though they were managed correctly within XCode. The correct invocation, for a target other than the project's main target is
sudo xcodebuild -target Trainer install
Previously, the first invocation would work, the product would be installed even though the scheme doesn't really include an "Install" action. This is clearly no longer so with XCode 7.1. The reason I couldn't use -target instead of -scheme previously, was because my target was dependent on a framework in another project, which was added to my main project (the external project was added, not just the framework). All dependencies were set up correctly in my main project, and from the command line it worked only when specifying the scheme, not when specifying the target. When running xcodebuild with -target specified, xcodebuild would not find the modules in the external project (a Swift framework).
I have now figured out the reason for this. The project which contained the external framework was not set up correctly. It was set up to install the framework into a bogus location (/tmp/ProjectName.dst/Library/Frameworks, which is the default). In addition, my main project needed to add /Library/Frameworks into the framework search paths. It seems that when the project is built inside XCode, or for archiving etc... libraries and executables are built into a "private" folder structure separate from the system itself. When running xcodebuild install, however, it tries to install the external frameworks into the proper system folders, and link it there. Therefore, setups that work inside XCode may not work when running 'xcodebuild'.
EDIT: It works now, but StackOverflow won't let me mark it as correct before two days.

How do you fix "code object is not signed at all In subcomponent:" in Xcode 6, Mac OS X Yosemite or Mavericks?

When compiling my application I'm getting the following error:
CodeSign /Users/pupeno/Library/Developer/Xcode/DerivedData/ProjectX-cynmgyozflnwbpamwnpsnhgshuyq/Build/Products/Debug/Project\ X.app
cd /Users/pupeno/Projects/ProjectX
export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
Signing Identity: "Mac Developer: José Fernández (G4PM7K38JH)"
/usr/bin/codesign --force --sign A21FB31766DDCBB28FBB4E4DD86E3743024A45F3 --entitlements /Users/pupeno/Library/Developer/Xcode/DerivedData/ProjectX-cynmgyozflnwbpamwnpsnhgshuyq/Build/Intermediates/ProjectX.build/Debug/App.build/Project\ X.app.xcent --requirements =designated\ =>\ anchor\ apple\ generic\ \ and\ identifier\ \"$self.identifier\"\ and\ ((cert\ leaf[field.1.2.840.113635.100.6.1.9]\ exists)\ or\ (\ certificate\ 1[field.1.2.840.113635.100.6.2.6]\ exists\ and\ certificate\ leaf[field.1.2.840.113635.100.6.1.13]\ exists\ \ and\ certificate\ leaf[subject.OU]\ =\ \"XHT4M2DATL\"\ )) /Users/pupeno/Library/Developer/Xcode/DerivedData/ProjectX-cynmgyozflnwbpamwnpsnhgshuyq/Build/Products/Debug/Project\ X.app
/Users/pupeno/Library/Developer/Xcode/DerivedData/ProjectX-cynmgyozflnwbpamwnpsnhgshuyq/Build/Products/Debug/Project X.app: code object is not signed at all
In subcomponent: /Users/pupeno/Library/Developer/Xcode/DerivedData/ProjectX-cynmgyozflnwbpamwnpsnhgshuyq/Build/Products/Debug/Project X.app/Contents/Frameworks/Paddle.framework
Command /usr/bin/codesign failed with exit code 1
I'm using two frameworks, Paddle and Sparkle and they are configured to sign on copy:
Looking for a solution to this problem I found many recommendations to do a --deep sign, which is officially discouraged by Apple (Using the codesign Tool's --deep Option Correctly).
I also found the article Code Signing and Mavericks which also explains that using --deep is wrong and offers an alternative: using a script to generate signatures for each framework. I think this is something that was needed before Xcode had the option to sign on copy, but I gave it a try anyway. It made no difference, I still get the same error. Looking at the logs, the bundles are getting signed with the "Sign on copy" option, so, adding that script caused them to get signed twice.
My code signing identity is configured as follows for the whole project and each target just inherits it:
I understand that's not the appropriate signature for Release, but for now, we are just trying to get this to build and run locally.
Any ideas what's wrong? Any ideas how to fix it?
I understand that
For me I had to go to the Project build settings and set Other Code Signing Flags to --deep. The problem was that my framework in the project was not signed.
For All who still are facing this issue, Please make sure 'Product Name' in build setting matches with 'Executable file' set in info.plist.
Generally when we duplicate exiting code, we simply change either product name or Executable file, and this mismatched creates a issue.
The problem was that the Framework, Paddle.framework, became corrupt. The symlinks were resolved to the files they were pointed to, so, compilation worked just fine, but signing didn't.
Re-downloading the framework and copying it into the project fixed the problem.
For me the solution was to re-Add a resource folder (checking Create groups instead of create folder references).
Adding ANOTHER thing to check if you get this error:
In the Build Phases pane for your Project's application target, make sure the Embed Frameworks phase comes before the Link Binary With Libraries phase:
I'm running macOS 11.2.3 and Xcode 12.4.
An Aside:
It's utterly ridiculous how fragile and broken code-signing remains. It's 2021 and this post alone has 87 different "fixes" to solve the same damn error message. There's just no excuse for wasting developers' time like this. Fix your IDE, Apple.
For me this problem was resolved by a simple "clean build folder" action, keyboard shortcut: shift+option+command+K.
I'll admit codesigning is still a black art to me, but in Xcode 6 I found that removing all of my signing scripts (which were necessary in Xcode 5, along with --deep flags) and additional signing flags, and just using the "codesign on copy" option in the Framework's Copy Files phase of the build worked flawlessly for me.
For me, it turned out that I had inadvertently added a bash build script to the target. Making sure I had no sneaky scripts accidentally copied into the target fixed the issue.
Product -> Cleanup build folder
Build/Compile project
for me, one of the frameworks I was including, had another of the frameworks marked as "embed and sign"... which you can't do... only the app should be doing that.
marking the grandchild framework as "do not embed" in the child framework, removed this issue.
I faced this problem after adding fastlane to upload screenshots to App Store Connect automatically. I had to remove fastlane from the project and clean the build folder to make it work again.
Using CocoaPods in the project it helped me to go to the Pods project, select a problem framework and set the correct developemtn team on Signing & Capabilities page or Build settings with All levels set.
In my case I both had a subproject and a subproject of that subproject (i.e. a sub-subproject) to which I had added the same Swift package dependency. Keeping it in the sub-subproject and removing it from the subproject solved the issue.
As shown by the number of answers here the causes for the error can be many.
In my experience building a complex project with multiple level of Frameworks, Static libraries from Swift packages and Pods you should follow these rules:
A Framework can't embed and sign another framework: only and App can do that.
A Framework can use a static library (from a Swift Package for instance) but the library must be present only in the Framework and not in the main App. If the same library is embedded in both Framework and main App, in some unknown circumstances, this error occurs.
Be sure to clean the build folder after each change to frameworks and library structure/embed

Are "Validate" and "Distribute" steps necessary for Direct Distribution of a Mac app?

I am working to automate the process of releasing a Mac application using xCode 5. The app is only distributed outside of the Mac App Store (Direct Distribution). I know that I can add a Run Script to be executed during the Build Phase to automate the process. I am currently using a ruby script from Craig Williams for appcast automation. The script is here: https://github.com/CraigWilliams/appcastautomation/blob/SnowLeopard/appcast_automation.rb
My question is: Are the Validate and Distribute steps necessary? Provided that code signing is completed, can I simply run the automation script and use the .zip file produced by the script or must I go through the steps outlined below and then process the "Exported" app using the script?
My current process is as follows:
Select "Archive" from xCode's Product menu.
Open Organizer and press "Validate" button.
Press "Distribute" and choose "Export Developer ID-signed
Application" then press "Next".
Select my Developer ID code signing certificate.
Press "Export" to save the MyApp.app file.
Once I have the "Exported" .app file, I am manually running the script via Terminal to create the .zip file required for Sparkle appcast. I am hoping to skip the xCode export process as a first step towards automated distribution.
Yes, it is possible to completely automate an app release process without needing to go through Xcode's Organizer to "Validate" and "Distribute" an application for Direct Distribution. It requires several Run Script Build Phases to be added to the target in XCode. This is what I ended up doing...
1) The first step was to code sign all frameworks AND the application bundle so that when the appcast automation script runs, the app that gets zipped is already code signed. This omits the need to export the app via Organizer. This Run Script is added immediately after all "copy" build phases.
IDENTITY="Developer ID Application: My Great Company."
FRAMEWORK_LOC="${BUILT_PRODUCTS_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"
codesign --verbose --force --sign "$IDENTITY" "$FRAMEWORK_LOC/Growl.framework/Versions/A"
codesign --verbose --force --sign "$IDENTITY" "$FRAMEWORK_LOC/Sparkle.framework/Versions/A"
codesign --verbose --force --sign "$IDENTITY" "$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME"
2) The 2nd Run Script executes a Ruby script that creates a .zip file of the app and an .xml file for appcast distribution via Sparkle. The original script came from here: https://github.com/CraigWilliams/appcastautomation/blob/SnowLeopard/appcast_automation.rb
I have customized the script to also copy the unzipped app to another folder that is later used to automagically create a .dmg file.
The 2nd run script is simply:
script_file="appcast_automation.rb"
$SRCROOT/$PRODUCT_NAME/${script_file}
3) The 3rd Run Script creates a .dmg file with a custom icon, background, version, license agreement, etc... I use DropDMG's command-line tool (http://c-command.com/dropdmg/) to create the .dmg file. I have added the wm_license and wm_layout directories into the Xcode project so the script has access to them and they are versioned using git.
This Run Script is set to "Run script only when installing".
VERSIONNUM=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${PROJECT_DIR}/${INFOPLIST_FILE}")
layout_folder="${PROJECT_DIR}/${PROJECT_NAME}/wm_layout"
license_folder="${PROJECT_DIR}/${PROJECT_NAME}/wm_license"
dmg_folder="/Users/username/Desktop/WindowMizer/${PROJECT_NAME}_$VERSIONNUM/${PROJECT_NAME}"
dropdmg --custom-icon --license-folder=$license_folder --layout-folder=$layout_folder $dmg_folder
The list of Run Scripts and the automation files in Xcode looks like this:
So, by simply choosing "Archive" in Xcode, I end up with: a .zip file and .xml files for automatic updates via Sparkle and a .dmg file for first-time (new) downloads. The end result is this...
Everything is code-signed and ready to deploy. The only thing left to do is to upload the files to the server, which could be automated, but I prefer to do that part manually.
When time permits, and if I am allowed, I will post my modified copy of appcast_automation.rb in a github repository and add a link to it from here.
Hope this helps someone else!

Trouble packaging and signing iOS apps built with Cordova CLI

Until now, all of my experience compiling PhoneGap apps has been via the excellent PhoneGap:Build service. However, I now find myself in a situation where I need to compile locally, because I need to use a plugin that includes a binary file, which precludes it from being included for use with PG:B.
So for these reasons, I need to compile locally. "Great!" I thought, I'll just use the new CLI...
I have developed my app, and I can test it on-device via deploy over USB from Xcode, but trying to get a release build, and sign it, with the provisioning profile embedded, has been a nightmare.
For completeness, this is the basic outline of everything I've done, aside from the app development itself.
$ pwd
/users/adam/dev/myapp/mobile/
$ cordova create build_local com.foo.bar MyApp
Creating a new cordova project with name "MyApp" and id "com.foo.bar" at location "/Users/adam/DEV/myapp/build_local"
$ cd build_local
$ cordova platform add ios
Creating ios project...
$ cordova platform add android
Creating android project...
Creating Cordova project for the Android platform:
Path: platforms/android
Package: com.foo.bar
Name: MyApp
Android target: android-19
Copying template files...
<snip>
Project successfully created.
$ cordova plugin add https://github.com/hazemhagrass/BackgroundJS
Fetching plugin "https://github.com/hazemhagrass/BackgroundJS" via git clone
Installing com.badrit.BackgroundJS (android)
Fetching plugin "https://github.com/apache/cordova-plugin-device.git" via git clone
Installing org.apache.cordova.device (android)
Installing com.badrit.BackgroundJS (ios)
Installing org.apache.cordova.device (ios)
$ cordova plugin add de.appplant.cordova.plugin.local-notification
Fetching plugin "de.appplant.cordova.plugin.local-notification" via plugin registry
Installing de.appplant.cordova.plugin.local-notification (android)
Installing de.appplant.cordova.plugin.local-notification (ios)
$ cordova plugin add https://github.com/kdzwinel/phonegap-estimotebeacons
Fetching plugin "https://github.com/kdzwinel/phonegap-estimotebeacons" via git clone
Installing pl.makingwaves.estimotebeacons (android)
Installing pl.makingwaves.estimotebeacons (ios)
For what it's worth, this last plugin is the reason that I have to compile locally.
Now, here's one other potential monkey wrench: This app is actually two apps. It's the same core codebase, merged into two different deployment branches of the repo, one for each client. So each app will have its own id, name, and config stuff. Because of this, I actually have more than one cordova project folder (1 for each final app) and after creating each project through the steps above, I remove the generated www folder and replace it with a symlink to the shared www folder that exists outside of these phonegap project directories.
This is supported behavior; the CLI allows you to generate your app with a symlink via the --link-to flag (see cordova help create for details). However, doing so seems to have issues; so I've resorted to doing all of the app config up front and then replacing the generated www folder with a symlink after everything is ready to compile.
At this point, I can deploy to either the iOS simulator or Android emulator, and I can deploy to devices over USB, and everything works just fine; all of my plugins are available and function as expected. So I'm ready to compile a release build. Android is easy. iOS, not so much.
$ cordova build ios
<snip>
** BUILD SUCCEEDED **
However, this is a DEV build. The generated file is in the build/emulator/ folder, and when I attempt to sign it, I'm told that it's not signed because of the I386 architecture (which indicates that it's a development build).
$ xcrun -sdk iphoneos PackageApplication -v "platforms/ios/build/emulator/MyApp.app" -o "/users/adam/dev/myapp/MyApp.ipa" --sign "iPhone Distribution: {our cert name} ({our cert id})"
<snip>
Codesign check fails : platforms/ios/build/emulator/MyApp.app: code object is not signed at all
In architecture: i386
<snip>
I've attempted to generate a release build from the cordova CLI. I haven't been able to find the --release flag documented anywhere, but the CLI doesn't complain, and it usually does if it doesn't recognize a flag.
$ cordova build ios --release
<same result as previously>
Attempting to sign this build results in the same problem.
At this point, I started attempting to work directly in Xcode. I've set the .mobileprovision file and the signing credentials up appropriately, to the best of my knowledge:
With these values set, Xcode no longer allows me to build:
So I'm stuck: I have no choice but to build locally, and I can't figure out how to get it to build for release and sign! Please help!
Additionally, if I attempt to embed a provisioning profile, that fails because of an issue with entitlements. I'm not exactly sure what this means, but I'm hopeful that it's a result of working with a dev build, and resolving that will resolve this as well.
$ test -e ~/.ios/DEV.mobileprovision && echo exists
exists
$ xcrun -sdk iphoneos PackageApplication -v "platforms/ios/build/emulator/MyApp.app" -o "/users/adam/dev/myapp/MyApp.ipa" --embed "~/.ios/DEV.mobileprovision"
<snip>
error: Failed to read entitlements from '/var/folders/zs/j2hmt69n12sbjm6gyn0m_q4c0000gn/T/tyYvYPQKf3/Payload/MyApp.app'
Update 1:
This SO question helped in one regard. I don't know how the active scheme (I'm not really sure what that means, but that's the tooltip when I hover over the control) got changed as part of specifying keys/etc, but clearly it did. Changing this back to an iOS Device, like iPhone, allows me to build my project, and even Archive (which, to the best of my understanding, means it's creating the .ipa file I need to submit to the app store), but I can't find the archived file. Where should it be? Can I define this in a setting somewhere in Xcode?
Update 2:
By fiddling with certificates and provisioning profiles I've finally been able to create an archive from Xcode, which I've been told is a release build (is it?). Ideally I would like to be able to build from the command line so that I can automate it as much as possible, so that's where I'll be picking up in the morning. Any advice on that front would be quite welcome!
If you managed to create an archive in Xcode, then your signing certificate and provisioning profiles are known to Xcode, so cordova build ios --release --device should make it.
The steps are:
1) Import your iOS developer certificate for production to the keychain by downloading and double clicking on it in Finder (or get it via Xcode)
2) Download your provisioning profile (with the App ID set to the id attribute of the widget element in config.xml) and double click it on Finder so it goes to the Xcode provisioning profile store
3) cordova build ios --release --device
it looks like you're trying to sign the app with a wildcard provisioning profile (the XCode screenshot). Can you try creating and downloading a distribution certificate and provprofile to your Mac? Then import the .cer file in the keychain access app (doubleclicking should suffice) and doubleclick the provprofile as well.
Now you should be able to select the appropriate values from the release dropdowns in the XCode build settings.
Hope this helps somewhat...
Eddy
One other issue I am seeing from your screenshot is I don't think you can Build an Archive (Release) version using the Developer Signing Idenetity, you would need to create a Distribution certificate and use that one for the Release (Archive) version.

Resources