2021-03-20
The content of this post is outdated. If you need help setting up codesigning for Endpoint Security on Bitrise, ping me on social media.
Disclaimer: while writing this post, I am employed at Bitrise to work on the build infrastructure
I have decided to play a bit with the "new" macOS Endpoint Security framework, and oh boy, am I disappointed. To be fair, Endpoint Security is a pretty powerful tool, which is easy to use once set up correctly. One needs to invest an incredible amount of time & patience to get an ES app up & running.:
One can utilize the Endpoint Security framework in different macOS application setups:
I have tried both ways and decided to go with the "official" way. System extension makes it harder for an average user to fiddle with the application, and signing/distribution is way more straightforward. Plus, I need my application to be MDM friendly.
While not receiving my requested entitlement, I've started to look for a way to be able to run & test my application without disabling SIP on my machine. First, I tried working with a VM on my local machine, but the whole development flow was chunky and didn't feel right. (It also took a considerable amount of performance toll on my MacBook). Trial two was setting up a CI/CD workflow at some provider. I am already familiar with Bitrise, so it was an obvious choice. Just as I started to work on the CI/CD flow, I got my entitlements, so the workflow does utilize the provisioning profiles.
You will need to fill out this form describing your use case and the nature of your application. This way, Apple may refuse to grant your request, but in return, they might "borrow" your application idea :) I got lucky as my request took a little less than a month.
Here comes the trick: I happen to know that on Bitrise Gen2 architecture, the VMs of a given stack share the same UDID, so essentially I can register them as a single device. At the moment, the UDID for the Xcode 13.2.1 (Monterey) is 9C256403-D331-4775-943E-7B060C2148F0. Please note that this UDID changes every few months or so. In that case, you need to re-generate the Provisioning Profiles & re-add them, as I will describe later.
This trick will only work when using Gen2 OR xcode 13.1 and above.Use this form to generate a signing certificate. If you already have one, skip the step.
I have generated two provisioning profiles: One for the extension and the other for the "host" application bundle.
The application bundle profile needs to have the System Extension entitlement. The App ID should be something like com.org.application
The extension profile needs to have the Endpoint Security entitlement. The App ID should be something like com.org.application.extension
Hypothetically, as an alternative you may use a wildcard App ID and add the two entitlements to the single profile. In each case, don't forget to add the Bitrise VM device you have registered in step 2.
You may use this example project to mimic the directory structure and configurations. Setup signing for your targets (application & extension) as you normally do for other xcode projects. Please choose "Manual Signing" instead of Automatic. If you want Unit Tests, you may add a Test scheme as a third target. As for the testing scheme, a plain "Manual" development signing certificate will suffice without a Provisioning Profile.
Following these steps, you should be all set to execute builds and tests for the system extension. I use the following scripts respectively:
# for tests
xcodebuild -project "project.xcodeproj" test -scheme app -allowProvisioningUpdates | xcbeautify
# for build
xcodebuild -project "project.xcodeproj" build -alltargets | xcbeautify
Nothing fancy here, as I just want the app to compile.
Apple may convince me that Endpoint Security and other entitled API usage need to be restricted & requires permission in production, but why are they gatekeeping the development usage so much? If they insist that the developers have to go through an approval process, then at least evaluation shouldn't take weeks or months. And why not limit only the distribution? Why is it accepted that I need to disable SIP on my Mac (rather than paying $99 and waiting for approval) to be able to experiment?
After adding a Unit Test scheme to the project, only the Host Application is available for selection as a test target. It means that by default, you cannot write Unit Tests for the extension codebase because the compiler won't know about the source files (based on my shallow understanding of Swift tooling). To work around this, click on the test target > Build Phases > Compile Sources > Add the extension's swift files that you want to include in the Unit Tests.
ioreg -d2 -c IOPlatformExpertDevice | awk -F\" '/IOPlatformUUID/{print $(NF-1)}'